Compare commits

..

No commits in common. 'master' and 'v0.3.0' have entirely different histories.

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

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

7
.gitignore vendored

@ -1,6 +1,3 @@
selene.toml
lua/navigator.lua.bak
tests/fixtures/tests
.vim/
*cache*/
*target*/
tests/fixtures/tests

@ -1,6 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"Lua.workspace.library": [
"${3rd}/luassert/library"
]
}

332
.tags

@ -1,332 +0,0 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_EXCMD number /number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
!_TAG_PROC_CWD /home/ray/github/ray-x/navigator.lua/ //
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 5.9.0 /227c65e76/
Custom_fold_text lua/navigator/foldts.lua 20;" f
Fix lua/navigator/protocal.txt 374;" f
["sumneko_lua"] issue130/init.lua 62;" f
["tsserver"] issue130/init.lua 71;" f
['<Tab>'] playground/init.lua 72;" f
['sumneko_lua'] playground/init_130.lua 34;" f
['sumneko_lua'] playground/init_131.lua 22;" f
['sumneko_lua'] playground/init_lsp_installer.lua 22;" f
['tsserver'] playground/init_130.lua 43;" f
['tsserver'] playground/init_131.lua 31;" f
['tsserver'] playground/init_lsp_installer.lua 31;" f
\x21 tests/fixtures/tests 133;" f
_ lua/navigator/util.lua 300;" f
_update_sign lua/navigator/codeAction.lua 44;" f
_update_sign lua/navigator/codelens.lua 26;" f
_update_virtual_text lua/navigator/codeAction.lua 27;" f
action_virtual_call_back lua/navigator/codeAction.lua 141;" f
add lua/navigator/lspclient/clients.lua 54;" f
add_highlight lua/navigator/lspclient/highlight.lua 34;" f unknown:M
add_locs lua/navigator/dochighlight.lua 15;" f
add_servers lua/navigator/lspclient/clients.lua 680;" f
add_workspace_folder lua/navigator/workspace.lua 9;" f unknown:M
adjust_foldend lua/navigator/foldlsp.lua 120;" f unknown:M
adjust_foldstart lua/navigator/foldlsp.lua 116;" f unknown:M
async thread.lua 4;" f
async_hdlr lua/navigator/reference.lua 139;" f unknown:M
async_ref lua/navigator/reference.lua 148;" f
autocmd lua/navigator/lspclient/mapping.lua 216;" f
before lua/navigator/dochighlight.lua 125;" f
buf_func lua/navigator/treesitter.lua 442;" f unknown:M
buf_ts lua/navigator/treesitter.lua 489;" f unknown:M
bufs_ts lua/navigator/treesitter.lua 511;" f unknown:M
call_async lua/navigator/lspwrapper.lua 153;" f unknown:M
call_hierarchy_handler lua/navigator/cclshierarchy.lua 12;" f
call_hierarchy_handler lua/navigator/hierarchy.lua 12;" f
call_sync lua/navigator/lspwrapper.lua 145;" f unknown:M
callback lua/navigator/lspwrapper.lua 155;" f
check_cap lua/navigator/lspclient/mapping.lua 84;" f
check_capabilities lua/navigator/lspwrapper.lua 121;" f unknown:M
check_lhs lua/navigator/lspwrapper.lua 31;" f
clear_all_buf lua/navigator/util.lua 380;" f unknown:M
clear_buf lua/navigator/util.lua 366;" f unknown:M
clear_diag_VT lua/navigator/diagnostics.lua 325;" f
clear_usage_highlights lua/navigator/treesitter.lua 612;" f unknown:M
cmd_nohl lua/navigator/dochighlight.lua 201;" f
cmp_kind lua/navigator/lspclient/lspkind.lua 128;" f unknown:lspkind
code_action lua/navigator/codeAction.lua 161;" f unknown:code_action
code_action_prompt lua/navigator/codeAction.lua 188;" f unknown:code_action
code_action_req lua/navigator/codeAction.lua 145;" f
codelens_hdlr lua/navigator/codelens.lua 49;" f
comp_kind lua/navigator/lspclient/lspkind.lua 120;" f unknown:lspkind
config lua/navigator/diagnostics.lua 474;" f unknown:M
config playground/init.lua 32;" f
config playground/init.lua 47;" f
config playground/init.lua 60;" f
config playground/init_131.lua 17;" f
config playground/init_131.lua 51;" f
config playground/init_lsp_installer.lua 17;" f
config playground/init_lsp_installer.lua 51;" f
config playground/init_ts_only.lua 35;" f
config playground/init_ts_only.lua 52;" f
config_values lua/navigator.lua 212;" f unknown:M
config_values lua/navigator.lua.bak 47;" f unknown:M
ctags lua/navigator/ctags.lua 133;" f
ctags_gen lua/navigator/ctags.lua 54;" f
ctags_symbols lua/navigator/ctags.lua 85;" f
curriedDot playground/js/curry.js 1;" f
cut lua/navigator/lru.lua 60;" f
debounce_trailing lua/navigator/debounce.lua 3;" f unknown:M
debug_folds lua/navigator/foldlsp.lua 82;" f unknown:M
def lua/navigator/definition.lua 145;" f
def_preview lua/navigator/definition.lua 41;" f
definition_hdlr README.md 759;" f
definition_hdlr doc/navigator.txt 662;" f
definition_hdlr lua/navigator/definition.lua 8;" f
del lua/navigator/lru.lua 95;" f
del_keymap lua/navigator/lspclient/mapping.lua 131;" f
delete lua/navigator/lru.lua 145;" f
deprecated lua/navigator.lua 117;" f unknown:M
diag_hdlr lua/navigator/diagnostics.lua 196;" f
diagnositc_config_sign lua/navigator/lspclient/highlight.lua 7;" f unknown:M
dirname lua/navigator/lspclient/clients.lua 85;" f
disable lua/navigator/codelens.lua 99;" f unknown:M
displayName playground/js/closure.js 3;" f
documentHighlight lua/navigator/dochighlight.lua 218;" f
document_symbol_handler lua/navigator/symbols.lua 43;" f unknown:M
document_symbols lua/navigator/symbols.lua 21;" f unknown:M
empty lua/navigator/util.lua 425;" f unknown:M
encoding lua/navigator/util.lua 436;" f unknown:M
entry_to_item lua/navigator/ctags.lua 9;" f
error lua/navigator/util.lua 203;" f unknown:M
error lua/navigator/util.lua 460;" f unknown:M
error_marker lua/navigator/diagnostics.lua 57;" f
exclude lua/navigator/util.lua 341;" f unknown:M
expand playground/init.lua 65;" f
extend_config lua/navigator.lua 138;" f
extend_config lua/navigator.lua.bak 27;" f
extension lua/navigator/render.lua 12;" f
extract_result lua/navigator/lspwrapper.lua 109;" f
file_exists lua/navigator/util.lua 75;" f unknown:M
filename lua/navigator/render.lua 5;" f
find_definition lua/navigator/treesitter.lua 75;" f unknown:M
find_ts_func_by_range lua/navigator/lspwrapper.lua 246;" f
fmt lua/navigator/util.lua 208;" f unknown:M
fnamemodify lua/navigator/lspwrapper.lua 56;" f
fold_handler lua/navigator/foldlsp.lua 90;" f unknown:M
folds_levels lua/navigator/foldts.lua 53;" f
format_hdl lua/navigator/formatting.lua 4;" f
func thread.lua 1;" f
get lua/navigator/lru.lua 112;" f
getArgs lua/navigator/util.lua 245;" f unknown:M
getDir lua/navigator/util.lua 119;" f
get_all_nodes lua/navigator/treesitter.lua 267;" f
get_base lua/navigator/util.lua 109;" f unknown:M
get_cfg lua/navigator/lspclient/clients.lua 685;" f
get_count lua/navigator/diagnostics.lua 49;" f
get_current_winid lua/navigator/codeAction.lua 23;" f
get_current_winid lua/navigator/util.lua 387;" f unknown:M
get_data_from_file lua/navigator/util.lua 36;" f unknown:M
get_definitions lua/navigator/treesitter.lua 111;" f
get_fold_indic lua/navigator/foldlsp.lua 130;" f unknown:M
get_fold_indic lua/navigator/foldts.lua 162;" f unknown:M
get_icon lua/navigator/treesitter.lua 27;" f
get_keymaps_help lua/navigator/lspclient/mapping.lua 333;" f unknown:M
get_line_diagnostic lua/navigator/diagnostics.lua 452;" f unknown:M
get_namespace lua/navigator/codeAction.lua 19;" f
get_node_at_line lua/navigator/treesitter.lua 561;" f unknown:M
get_node_at_pos lua/navigator/treesitter.lua 616;" f unknown:M
get_node_scope lua/navigator/treesitter.lua 632;" f unknown:M
get_pads lua/navigator/render.lua 17;" f
get_relative_path lua/navigator/util.lua 137;" f unknown:M
get_scope lua/navigator/treesitter.lua 151;" f
get_smallest_context lua/navigator/treesitter.lua 213;" f
get_symbol lua/navigator/definition.lua 36;" f
get_symbol lua/navigator/dochighlight.lua 11;" f
get_symbol lua/navigator/lspwrapper.lua 24;" f unknown:M
goto_adjacent_usage lua/navigator/treesitter.lua 230;" f unknown:M
goto_adjent_reference lua/navigator/dochighlight.lua 161;" f
goto_definition lua/navigator/treesitter.lua 35;" f unknown:M
goto_next_usage lua/navigator/treesitter.lua 256;" f unknown:M
goto_previous_usage lua/navigator/treesitter.lua 259;" f unknown:M
handle_document_highlight lua/navigator/dochighlight.lua 141;" f
handlers['textDocument/codeLens'] lua/navigator/codelens.lua 75;" f unknown:vim.lsp
handlers['textDocument/documentHighlight'] lua/navigator/dochighlight.lua 229;" f unknown:vim.lsp
hi_symbol lua/navigator/dochighlight.lua 46;" f
hide_diagnostic lua/navigator/diagnostics.lua 336;" f unknown:M
highlight_usages lua/navigator/treesitter.lua 588;" f unknown:M
i tests/fixtures/tests 122;" f
implementation lua/navigator/implementation.lua 24;" f unknown:M
implementation_handler lua/navigator/implementation.lua 18;" f
incoming_calls lua/navigator/cclshierarchy.lua 72;" f unknown:M
incoming_calls lua/navigator/hierarchy.lua 80;" f unknown:M
incoming_calls_handler lua/navigator/cclshierarchy.lua 54;" f
incoming_calls_handler lua/navigator/hierarchy.lua 63;" f
info lua/navigator.lua 7;" f
info lua/navigator/util.lua 197;" f unknown:M
info lua/navigator/util.lua 464;" f unknown:M
init lua/navigator/lazyloader.lua 2;" f
init lua/navigator/lspclient/lspkind.lua 132;" f unknown:lspkind
inline lua/navigator/codelens.lua 117;" f unknown:M
io_read lua/navigator/util.lua 64;" f unknown:M
key lua/navigator/treesitter.lua 263;" f
lines_from_locations lua/navigator/lspwrapper.lua 55;" f unknown:M
list_workspace_folders lua/navigator/workspace.lua 92;" f unknown:M
load lua/navigator/lazyloader.lua 46;" f
load_cfg lua/navigator/lspclient/clients.lua 372;" f
load_plugins playground/init.lua 26;" f
load_plugins playground/init_130.lua 13;" f
load_plugins playground/init_131.lua 10;" f
load_plugins playground/init_lsp_installer.lua 10;" f
load_plugins playground/init_ts_only.lua 26;" f
location_handler lua/navigator/implementation.lua 10;" f
locations_to_items lua/navigator/lspwrapper.lua 315;" f unknown:M
log lua/navigator/util.lua 194;" f unknown:M
lru_pairs lua/navigator/lru.lua 164;" f
lsp_startup lua/navigator/lspclient/clients.lua 462;" f
main README.md 36;" f
main doc/navigator.txt 86;" f
makeFreeSpace lua/navigator/lru.lua 105;" f
makeFunc playground/js/closure.js 1;" f
map lua/navigator/util.lua 91;" f unknown:M
match_parameter lua/navigator/signature.lua 5;" f
matches lua/navigator/foldts.lua 69;" f
merge lua/navigator/util.lua 84;" f unknown:M
mk_handler lua/navigator/util.lua 413;" f unknown:M
mynext lua/navigator/lru.lua 149;" f
nav_doc_hl lua/navigator/dochighlight.lua 208;" f
new lua/navigator/lru.lua 32;" f unknown:lru
new_list_view lua/navigator/gui.lua 10;" f unknown:M
node_in_range lua/navigator/treesitter.lua 547;" f
node_is_definination lua/navigator/treesitter.lua 51;" f
nohl lua/navigator/dochighlight.lua 34;" f
nv_ref_async lua/navigator/reference.lua 109;" f
nvim_0_6_1 lua/navigator/util.lua 391;" f unknown:M
nvim_0_8 lua/navigator/util.lua 402;" f unknown:M
oldval tests/fixtures/tests 124;" f
on_attach README.md 243;" f
on_attach README.md 303;" f
on_attach README.md 583;" f
on_attach doc/navigator.txt 247;" f
on_attach doc/navigator.txt 289;" f
on_attach doc/navigator.txt 505;" f
on_attach issue130/init.lua 72;" f unknown:options
on_attach lua/navigator.lua 26;" f
on_attach lua/navigator/foldlsp.lua 25;" f unknown:M
on_attach lua/navigator/foldts.lua 15;" f unknown:M
on_attach lua/navigator/lspclient/attach.lua 10;" f unknown:M
on_attach lua/navigator/lspclient/clients.lua 180;" f
on_attach lua/navigator/lspclient/clients.lua 204;" f
on_attach lua/navigator/lspclient/clients.lua 552;" f unknown:cfg
on_attach lua/navigator/lspclient/clients.lua 564;" f unknown:cfg
on_attach lua/navigator/lspclient/clients.lua 576;" f unknown:cfg
on_attach lua/navigator/lspclient/clients.lua 604;" f unknown:cfg
on_attach lua/navigator/lspclient/clients.lua 660;" f unknown:cfg
on_attach playground/init_130.lua 44;" f unknown:options
on_attach playground/init_131.lua 32;" f unknown:options
on_attach playground/init_lsp_installer.lua 32;" f unknown:options
on_confirm lua/navigator/workspace.lua 58;" f
on_exit lua/navigator/ctags.lua 73;" f
on_filetype lua/navigator/lspclient/clients.lua 806;" f
on_init lua/navigator/lspclient/clients.lua 594;" f unknown:cfg
on_input_filter lua/navigator/workspace.lua 65;" f
on_move lua/navigator/workspace.lua 99;" f
on_new_config lua/navigator/lspclient/clients.lua 247;" f
on_stdout lua/navigator/ctags.lua 69;" f
open_file lua/navigator/util.lua 326;" f unknown:M
open_log lua/navigator/util.lua 274;" f unknown:M
open_lsp_log lua/navigator/lspclient/config.lua 22;" f unknown:M
order_locations lua/navigator/lspwrapper.lua 262;" f
outgoing_calls lua/navigator/cclshierarchy.lua 89;" f unknown:M
outgoing_calls lua/navigator/hierarchy.lua 91;" f unknown:M
outgoing_calls_handler lua/navigator/cclshierarchy.lua 64;" f
outgoing_calls_handler lua/navigator/hierarchy.lua 72;" f
p lua/navigator/util.lua 259;" f unknown:M
pack lua/navigator/util.lua 279;" f unknown:table
partial lua/navigator/util.lua 419;" f unknown:M
path_cur lua/navigator/util.lua 23;" f unknown:M
path_sep lua/navigator/util.lua 12;" f unknown:M
prepare_for_render lua/navigator/render.lua 51;" f unknown:M
prepare_node lua/navigator/treesitter.lua 138;" f
printError lua/navigator/util.lua 263;" f unknown:M
prompt lua/navigator/workspace.lua 12;" f
prompt lua/navigator/workspace.lua 22;" f
prompt lua/navigator/workspace.lua 30;" f
quickfix_extract lua/navigator/util.lua 223;" f unknown:M
range_code_action lua/navigator/codeAction.lua 173;" f unknown:code_action
ref lua/navigator/reference.lua 202;" f
ref_hdlr lua/navigator/reference.lua 136;" f
ref_req lua/navigator/reference.lua 185;" f
ref_view lua/navigator/reference.lua 13;" f
refresh lua/navigator/codelens.lua 86;" f unknown:M
reload lua/navigator/util.lua 269;" f unknown:M
reload_lsp lua/navigator/lspclient/config.lua 7;" f unknown:M
remove_workspace_folder lua/navigator/workspace.lua 17;" f unknown:M
rename lua/navigator/rename.lua 6;" f unknown:M
render_action_virtual_text lua/navigator/codeAction.lua 79;" f unknown:code_action
request lua/navigator/lspwrapper.lua 464;" f unknown:M
root_dir lua/navigator/lspclient/clients.lua 120;" f
root_dir lua/navigator/lspclient/clients.lua 164;" f
root_dir lua/navigator/lspclient/clients.lua 187;" f
root_dir lua/navigator/lspclient/clients.lua 99;" f
round lua/navigator/util.lua 32;" f unknown:M
run_action lua/navigator/codelens.lua 105;" f unknown:M
select lua/navigator/gui.lua 59;" f unknown:M
set lua/navigator/lru.lua 122;" f
setNewest lua/navigator/lru.lua 84;" f
set_cmds lua/navigator/lspclient/mapping.lua 118;" f
set_diag_loclist lua/navigator/diagnostics.lua 383;" f unknown:M
set_event_handler lua/navigator/lspclient/mapping.lua 228;" f
set_keymap lua/navigator/lspclient/mapping.lua 135;" f
set_mapping lua/navigator/lspclient/mapping.lua 124;" f
set_virt_eol lua/navigator/util.lua 356;" f unknown:M
setup lua/navigator.lua 216;" f unknown:M
setup lua/navigator.lua.bak 51;" f unknown:M
setup lua/navigator/codelens.lua 64;" f unknown:M
setup lua/navigator/lspclient/clients.lua 19;" f
setup lua/navigator/lspclient/clients.lua 696;" f
setup lua/navigator/lspclient/mapping.lua 273;" f unknown:M
setup_fmt lua/navigator/lspclient/clients.lua 425;" f
setup_fold lua/navigator/foldts.lua 33;" f unknown:M
setup_plugin lua/navigator/foldlsp.lua 30;" f unknown:M
show lua/navigator/util.lua 283;" f unknown:M
show_buf_diagnostics lua/navigator/diagnostics.lua 351;" f unknown:M
show_diagnostics lua/navigator/diagnostics.lua 457;" f unknown:M
signature_handler lua/navigator/signature.lua 44;" f
slice_locations lua/navigator/lspwrapper.lua 280;" f
sort_select lua/navigator/codeAction.lua 154;" f
split lua/navigator/util.lua 212;" f unknown:M
split2 lua/navigator/util.lua 295;" f unknown:M
start_client lua/navigator.lua 243;" f unknown:vim.lsp
symbol_kind lua/navigator/lspclient/lspkind.lua 124;" f unknown:lspkind
symbol_to_items lua/navigator/lspwrapper.lua 425;" f unknown:M
symbols_to_items lua/navigator/lspwrapper.lua 75;" f unknown:M
testitem lua/navigator/ctags.lua 144;" f
throttle_leading lua/navigator/debounce.lua 14;" f unknown:M
title lua/navigator/protocal.txt 388;" f
title lua/navigator/protocal.txt 392;" f
toggle_diagnostics lua/navigator/diagnostics.lua 342;" f unknown:M
toggle_lspformat lua/navigator/lspclient/mapping.lua 254;" f unknown:M
trace lua/navigator/util.lua 200;" f unknown:M
trim_and_pad lua/navigator/util.lua 307;" f unknown:M
trim_level lua/navigator/foldts.lua 55;" f
ts_definition lua/navigator/lspwrapper.lua 207;" f
ts_functions lua/navigator/lspwrapper.lua 163;" f
type vim.toml 21;" f
type vim.toml 26;" f
type vim.toml 29;" f
type vim.toml 31;" f
unload lua/navigator/lspwrapper.lua 354;" f
update_capabilities lua/navigator/lspclient/clients.lua 442;" f
update_err_marker lua/navigator/diagnostics.lua 414;" f unknown:M
update_err_marker_async lua/navigator/diagnostics.lua 191;" f
update_folds lua/navigator/foldlsp.lua 62;" f unknown:M
warn lua/navigator.lua 3;" f
warn lua/navigator/util.lua 456;" f unknown:M
workspace_symbol lua/navigator/workspace.lua 28;" f unknown:M
workspace_symbol_handler lua/navigator/symbols.lua 103;" f unknown:M
workspace_symbol_live lua/navigator/workspace.lua 36;" f unknown:M
workspace_symbols lua/navigator/symbols.lua 9;" f unknown:M
~ lua/navigator/treesitter.lua 202;" f
~ lua/navigator/treesitter.lua 371;" f

@ -1,46 +1,40 @@
# Navigator
- Source code analysis and navigate tool
- Easy code navigation, view diagnostic errors, see relationships of functions, variables
- A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provides a better highlight but also help you analyse symbol context effectively.
- ctags fuzzy search & build ctags symbols
- 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 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
## Example: Javascript closure
#### Example: Javascript closure
The screenshot below shows javascript call tree 🌲 for variable `browser` within a closure. This feature parallels the LSP 'incoming & outgoing calls' feature. It is designed for the symbol analysis.
The following screenshot shows javascript call tree 🌲 of variable `browser` insides a closure. This feature is similar to incoming & outgoing calls from LSP. It is designed for the symbol analysis.
![navigator](https://user-images.githubusercontent.com/1681295/126022829-291a7a2e-4d24-4fde-8293-5ae61562e67d.jpg)
Explanation:
- The topmost entry in the floating window indicates there are 3 references for the symbol <span style="color:red"> _browser_ </span> within closure.js
- The first reference of browser is an assignment, an emoji 📝 indicates the value is modified in this line. In many
- The first line of floating windows shows there are 3 references for the symbol <span style="color:red"> _browser_ </span> in closure.js
- The first reference of browser is an assignment, an emoji 📝 indicates the value is changed in this line. In many
cases, we search for references to find out when the value changed.
- The second reference of `browser` is inside function `displayName` and `displayName` sit inside `makeFunc`, So you
will see `displayName{} <- makeFunc{}`
- The next occurrence of `browser` is located within the function `displayName`, which is nested inside `makeFunc`. Hence, the display reads `displayName{} <- makeFunc{}.`
- The final reference is akin to the previous one, except that since `browser` appears on the right side of the `=`, its value remains unaltered, and consequently, no emoji is displayed.
will see ` displayName{} <- makeFunc{}`
- The third similar to the second, as var browser is on the right side of '=', the value not changed in this line
and emoji is not shown.
## Example: C++ definition
#### Example: C++ definition
C++ example: search reference and definition
![cpp_ref](https://user-images.githubusercontent.com/1681295/119215215-8bd7a080-bb0f-11eb-82fc-8cdf1955e6e7.jpg)
You may find a 🦕 dinosaur(d) on the line of `Rectangle rect,` which means there is a definition (d for def) of rect in this line.
`<- f main()` means the definition is inside function main().
## Golang struct type
#### Golang struct type
Struct type references in multiple Go 󰟓 files
Struct type references in multiple Go files
![go_reference](https://user-images.githubusercontent.com/1681295/119123823-54b3b180-ba73-11eb-8790-097601e10f6a.gif)
@ -53,20 +47,13 @@ variable is:
- Defined
- Called
## Features
# Features:
- LSP easy setup. Support the most commonly used lsp clients setup. Dynamic lsp activation based on buffer type. This
also enables you to handle workspace with mixed types of codes (e.g. Go + javascript + yml). A better LSP default enables
* autocompletion *(e.g. nvim-cmp),
* codelens
* lsp folding
* go implementation
* incoming/outgoing call and ccls call hierarchy
* range formatting
- Out of box experience. 10 lines of minimum init.lua can turn your neovim into a full-featured LSP & Treesitter powered IDE
also enables you to handle workspace with mixed types of codes (e.g. Go + javascript + yml). A better default setup is
included for LSP clients.
- Lazy loading friendly.
- Out of box experience. 10 lines of minimum vimrc can turn your neovim into a full-featured LSP & Treesitter powered IDE
- UI with floating windows, navigator provides a visual way to manage and navigate through symbols, diagnostic errors, reference etc. It covers
all features(handler) provided by LSP from commonly used search reference, to less commonly used search for interface
@ -80,11 +67,11 @@ variable is:
- Async request with lsp.buf_request for reference search
- Treesitter symbol search. It is handy for large files (Some of LSP e.g. lua_ls, there is a 100kb file size limitation?). Also as LSP trying to hide details behind, Treesitter allows you to access all AST semantics.
- Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limitation?)
- FZY search with either native C (if gcc installed) or Lua-JIT
- LSP multiple symbols highlight/marker and hop between document references
- LSP multiple symbol highlight/marker and hop between document references
- Preview definination/references
@ -104,15 +91,7 @@ variable is:
- ccls call hierarchy (Non-standard `ccls/call` API) supports
- Incorporates a modified folding algorithm based on treesitter or LSP_fold, providing a user experience comparable to Visual Studio Code.
- Ensures end or closing brackets remain visible.
- Features specific functionality for comment folding.
- Enables the display of folded lines.
- Includes syntax highlighting capabilities (supported in Neovim version 0.10.x and above).
- Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
- Calltree: Display and expand Lsp incoming/outgoing calls hierarchy-tree with sidebar
- Syntax folding based on treesitter folding algorithm. (It behaves similar to vs-code)
- Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
@ -122,13 +101,11 @@ variable is:
- 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.
### Similar projects / special mentions
# Similar projects / special mentions:
- [nvim-lsputils](https://github.com/RishabhRD/nvim-lsputils)
- [nvim-fzy](https://github.com/mfussenegger/nvim-fzy.git)
@ -136,11 +113,10 @@ I'd like to go beyond what the system is offering.
- [lspsaga](https://github.com/glepnir/lspsaga.nvim)
- [fzf-lsp lsp with fzf as gui backend](https://github.com/gfanto/fzf-lsp.nvim)
- [nvim-treesitter-textobjects](https://github.com/nvim-treesitter/nvim-treesitter-textobjects)
- [inc-rename.nvim](https://github.com/smjonas/inc-rename.nvim)
## Install
# Install
Require nvim-0.9 or above, nightly (0.10 or greater) preferred
Require nvim-0.5.0 (a.k.a nightly)
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)).
@ -151,18 +127,14 @@ Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
Plug 'ray-x/navigator.lua'
```
Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
Note: Highly recommened: 'nvim-treesitter/nvim-treesitter'
Packer
```lua
use({
'ray-x/navigator.lua',
requires = {
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
{ 'neovim/nvim-lspconfig' },
},
})
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}}
```
## Setup
@ -193,6 +165,8 @@ call plug#end()
lua <<EOF
require'navigator'.setup()
EOF
```
You can remove your lspconfig.lua and use the hooks of navigator.lua. As the
@ -219,6 +193,8 @@ call plug#end()
lua <<EOF
require'navigator'.setup()
EOF
```
## Work with nvim-cmp and nvim-autopairs
@ -241,6 +217,7 @@ vim.cmd("autocmd FileType guihua_rust lua require('cmp').setup.buffer { enabled
...
}
```
## All configure options
@ -251,7 +228,6 @@ Nondefault configuration example:
require'navigator'.setup({
debug = false, -- log output, set to true and log path: ~/.cache/nvim/gh.log
-- slowdownd startup and some actions
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
@ -266,114 +242,45 @@ require'navigator'.setup({
-- end,
-- The attach code will apply to all LSP clients
ts_fold = {
enable = false,
comment_fold = true, -- fold with comment string
max_lines_scan_comments = 20, -- only fold when the fold level higher than this value
disable_filetypes = {'help', 'guihua', 'text'}, -- list of filetypes which doesn't fold using treesitter
}, -- modified version of treesitter folding
default_mapping = true, -- set to false if you will remap every key
keymaps = {{key = "gK", func = vim.lsp.declaration, desc = 'declaration'}}, -- a list of key maps
keymaps = {{key = "gK", func = "declaration()"}}, -- a list of key maps
-- this kepmap gK will override "gD" mapping function declaration() in default kepmap
-- please check mapping.lua for all keymaps
-- rule of overriding: if func and mode ('n' by default) is same
-- the key will be overridden
treesitter_analysis = true, -- treesitter variable context
treesitter_navigation = true, -- bool|table false: use lsp to navigate between symbol ']r/[r', table: a list of
--lang using TS navigation
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_condense = true, -- condense form for treesitter analysis
-- this value prevent slow in large projects, e.g. found 100000 reference in a project
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- 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 = { -- refer to lua/navigator.lua for more icons config
-- requires nerd fonts or nvim-web-devicons
icons = true,
icons = {
-- Code action
code_action_icon = "🏏", -- note: need terminal support, for those not support unicode, might crash
code_action_icon = "🏏",
-- Diagnostics
diagnostic_head = '🐛',
diagnostic_head_severity_1 = "🈲",
fold = {
prefix = '⚡', -- icon to show before the folding need to be 2 spaces in display width
separator = '', -- e.g. shows  3 lines 
},
-- refer to lua/navigator.lua for more icons setups
},
mason = false, -- set to true if you would like use the lsp installed by williamboman/mason
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
lsp = {
enable = true, -- skip lsp setup, and only use treesitter in navigator.
-- Use this if you are not using LSP servers, and only want to enable treesitter support.
-- If you only want to prevent navigator from touching your LSP server configs,
-- use `disable_lsp = "all"` instead.
-- If disabled, make sure add require('navigator.lspclient.mapping').setup({bufnr=bufnr, client=client}) in your
-- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
code_lens_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
document_highlight = true, -- LSP reference highlight,
-- it might already supported by you setup, e.g. LunarVim
format_on_save = true, -- {true|false} set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
-- table: {enable = {'lua', 'go'}, disable = {'javascript', 'typescript'}} to enable/disable specific language
-- enable: a whitelist of language that will be formatted on save
-- disable: a blacklist of language that will not be formatted on save
-- function: function(bufnr) return true end to enable/disable lsp format on save
format_options = {async=false}, -- async: disable by default, the option used in vim.lsp.buf.format({async={true|false}, name = 'xxx'})
disable_format_cap = {"sqlls", "lua_ls", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
-- If you using null-ls and want null-ls format your code
-- you should disable all other lsp and allow only null-ls.
-- disable_lsp = {'pylsd', 'sqlls'}, -- prevents navigator from setting up this list of servers.
-- if you use your own LSP setup, and don't want navigator to setup
-- any LSP server for you, use `disable_lsp = "all"`.
-- you may need to add this to your own on_attach hook:
-- require('navigator.lspclient.mapping').setup({bufnr=bufnr, client=client})
-- for e.g. denols and tsserver you may want to enable one lsp server at a time.
-- default value: {}
diagnostic = {
underline = true,
virtual_text = true, -- show virtual for diagnostic message
update_in_insert = false, -- update diagnostic message in insert mode
float = { -- setup for floating windows style
focusable = false,
sytle = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
},
hover = {
enable = true,
keymap = {
['<C-k>'] = {
go = function()
local w = vim.fn.expand('<cWORD>')
vim.cmd('GoDoc ' .. w)
end,
default = function()
local w = vim.fn.expand('<cWORD>')
vim.lsp.buf.workspace_symbol(w)
end,
},
},
format_on_save = true, -- set to false to disable lsp code format on save (if you are using prettier/efm/formater etc)
disable_format_cap = {"sqls", "sumneko_lua", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
disable_lsp = {'pylsd', 'sqlls'}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
-- only want to enable one lsp server
-- to disable all default config and use your own lsp setup set
-- disable_lsp = 'all'
-- Default {}
diagnostic_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_update_in_insert = false, -- update diagnostic message in insert mode
display_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to ignore it
-- set to 'trouble' to show diagnostcs in Trouble
disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to
ignore it
tsserver = {
filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetypes
},
ctags ={
cmd = 'ctags',
tagfile = 'tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
gopls = { -- gopls setting
on_attach = function(client, bufnr) -- on_attach for gopls
-- your special on attach here
@ -385,29 +292,19 @@ require'navigator'.setup({
gopls = {gofumpt = false} -- disable gofumpt etc,
}
},
-- the lsp setup can be a function, .e.g
gopls = function()
local go = pcall(require, "go")
if go then
local cfg = require("go.lsp").config()
cfg.on_attach = function(client)
client.server_capabilities.documentFormattingProvider = false -- efm/null-ls
end
return cfg
end
end,
lua_ls = {
sumneko_lua = {
sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server",
sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
},
servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients available based on filetype
-- but if you want navigator load e.g. `cmake` and `ltex` for you , you
servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients avalible based on filetype
-- but if you whant navigator load e.g. `cmake` and `ltex` for you , you
-- can put them in the `servers` list and navigator will auto load them.
-- you could still specify the custom config like this
-- cmake = {filetypes = {'cmake', 'makefile'}, single_file_support = false},
}
})
```
### LSP clients
@ -417,15 +314,15 @@ Built clients:
```lua
local servers = {
"angularls", "gopls", "tsserver", "flow", "bashls", "dockerls", "julials", "pylsp", "pyright",
"jedi_language_server", "jdtls", "lua_ls", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqlls", "denols", "graphql", "dartls", "dotls",
"jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls",
"kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp",
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls",
"sourcekit", "fsautocomplete", "vls", "hls"
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp"
}
```
Navigator will try to load available lsp server/client based on filetype. The clients has none default on_attach.
Navigator will try to load avalible lsp server/client based on filetype. The clients has none default on_attach.
incremental sync and debounce is enabled by navigator. And the lsp
snippet will be enabled. So you could use COQ and nvim-cmp snippet expand.
@ -434,14 +331,14 @@ Other than above setup, additional none default setup are used for following lsp
- gopls
- clangd
- rust_analyzer
- sqlls
- lua_ls
- sqls
- sumneko_lua
- pyright
- ccls
Please check [client setup](https://github.com/ray-x/navigator.lua/blob/26012cf9c172aa788a2e53018d94b32c5c75af75/lua/navigator/lspclient/clients.lua#L98-L234)
The plugin can work with multiple LSP, e.g sqlls+gopls+efm. But there are cases you may need to disable some of the
The plugin can work with multiple LSP, e.g sqls+gopls+efm. But there are cases you may need to disable some of the
servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use
pylsp+pyright+jedi
together. If you have multiple similar LSP installed and have trouble with the plugin, please enable only one at a time.
@ -451,13 +348,14 @@ together. If you have multiple similar LSP installed and have trouble with the p
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
Alternatively, update following option in setup(if you do not want a PR):
Also, an option in setup:
```lua
require'navigator'setup{lsp={servers={'cmake', 'lexls'}}}
```
Above option add cmake and lexls to the default server list
Above example add cmake and lexls to the default server list
### Disable a lsp client loading from navigator
@ -470,6 +368,7 @@ require'navigator'.setup({
pylsd={filetype={}}
}
})
```
Or:
@ -490,40 +389,34 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| mode | key | function |
| ---- | --------------- | ---------------------------------------------------------- |
| n | gr | async references, definitions and context |
| n | \<Leader>gr | show reference and context |
| n | gr | show reference and context |
| n | Gr | async references, definitions and context (experiential) |
| i | \<m-k\> | signature help |
| n | \<c-k\> | signature help |
| n | gW | workspace symbol fuzzy finder |
| n | gW | workspace symbol |
| n | gD | declaration |
| n | gd | definition |
| n | gt | type definition |
| n | g0 | document symbol |
| n | \<C-]\> | go to definition (if multiple show listview) |
| n | gp | definition preview (show Preview) |
| n | gP | type definition preview (show Preview) |
| n | gp | definition preview (Go to Preview) |
| n | \<C-LeftMouse\> | definition |
| n | g\<LeftMouse\> | implementation |
| n | \<Leader>gt | treesitter document symbol |
| n | \<Leader\>gT | treesitter symbol for all open buffers |
| n | \<Leader\> ct | ctags symbol search |
| n | \<Leader\> cg | ctags symbol generate |
| n | K | hover doc |
| n | \<Space\>ca | code action (when you see 🏏 ) |
| n | \<Space\>la | code lens action (when you see a codelens indicator) |
| v | \<Space\>ca | range code action (when you see 🏏 ) |
| v | \<Space\>cA | range code action (when you see 🏏 ) |
| n | \<Space\>rn | rename with floating window |
| n | \<Leader\>re | rename (lsp default) |
| n | \<Leader\>gi | hierarchy incoming calls |
| n | \<Leader\>go | hierarchy outgoing calls |
| n | \<Space\>ff | format buffer (LSP) |
| v | \<Space\>ff | format selection range (LSP) |
| n | gi | implementation |
| n | \<Space\> D | type definition |
| n | gL | show line diagnostic |
| n | gG | show diagnostic for all buffers |
| n | ]d | next diagnostic error or fallback |
| n | [d | previous diagnostic error or fallback |
| n | ]d | next diagnostic |
| n | [d | previous diagnostic |
| n | \<Leader\> dt | diagnostic toggle(enable/disable) |
| n | ]r | next treesitter reference/usage |
| n | [r | previous treesitter reference/usage |
@ -544,21 +437,20 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| n | \<Enter\> | open preview file in nvim/Apply action |
| n | \<ESC\> | close listview of floating window |
| i/n | \<C-e\> | close listview of floating window |
| n | \<C-q\> | close listview and send results to quickfix |
| i/n | \<C-b\> | previous page in listview |
| i/n | \<C-f\> | next page in listview |
| i/n | \<C-s\> | save the modification to preview window to file |
### Colors/Highlight
### Colors/Highlight:
You can override default highlight GuihuaListDark (listview) and GuihuaTextViewDark (code view) and GuihuaListHl (select item)
You can override default highlight GHListDark (listview) and GHTextViewDark (code view) and GHListHl (select item)
e.g.
```vim
hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GuihuaListHl guifg=#e0d8f4 guibg=#404254
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254
```
There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -572,169 +464,75 @@ LspDiagnosticsXXX are used for diagnostic. Please check highlight.lua and dochig
- treesitter (list treesitter symbols, object analysis)
- lsp-signature (better signature help)
The plugin can be loaded lazily (packer `opt = true` ), And it will check if optional plugins existence and load those plugins only if they existed.
The plugin can be loaded lazily (packer `opt = true` ), And it will check if optional plugins existance and load those plugins only if they existed.
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
## Integrate with mason (williamboman/mason.nvim)
## Integrat with lsp_installer (williamboman/nvim-lsp-installer)
If you are using mason and would like to use the lsp servers installed by mason. Please set
If you are using lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
```lua
mason = true -- mason user
```
In the config. Also please setup the lsp server from installer setup with `server:setup{opts}`
lsp_installer = true
for mason
```lua
use("williamboman/mason.nvim")
use({
"williamboman/mason-lspconfig.nvim",
config = function()
require("mason").setup()
require("mason-lspconfig").setup({})
end,
})
use({
"ray-x/navigator.lua",
requires = {
{ "ray-x/guihua.lua", run = "cd lua/fzy && make" },
{ "neovim/nvim-lspconfig" },
{ "nvim-treesitter/nvim-treesitter" },
},
config = function()
require("navigator").setup({
mason = true,
})
end,
})
```
Another way to setup mason is disable navigator lsp setup and using mason setup handlers, pylsp for example
```lua
use("williamboman/mason.nvim")
use({
"williamboman/mason-lspconfig.nvim",
config = function()
require("mason").setup()
require("mason-lspconfig").setup_handlers({
["pylsp"] = function()
require("lspconfig").pylsp.setup({
on_attach = function(client, bufnr)
require("navigator.lspclient.mapping").setup({ client = client, bufnr = bufnr }) -- setup navigator keymaps here,
require("navigator.dochighlight").documentHighlight(bufnr)
require("navigator.codeAction").code_action_prompt(bufnr)
end,
})
end,
})
require("mason-lspconfig").setup({})
end,
})
use({
"navigator.lua",
requires = {
{ "ray-x/guihua.lua", run = "cd lua/fzy && make" },
{ "nvim-lspconfig" },
{ "nvim-treesitter/nvim-treesitter" },
},
config = function()
require("navigator").setup({
mason = true,
lsp = { disable_lsp = { "pylsp" } }, -- disable pylsp setup from navigator
})
end,
})
```
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 mason.
Alternatively, Navigator can be used to startup the server installed by lsp-installer. Please do not call `server:setup{opts}` from lsp installer
as it will override the navigator setup
To start LSP installed by mason, please use following setups
To start LSP installed by lsp_installer, please use following setups
```lua
require'navigator'.setup({
-- mason = false -- default value is false
-- lsp_installer = false -- default value is false
lsp = {
tsserver = { cmd = {'your tsserver installed by mason'} }
-- e.g. tsserver = { cmd = {'/home/username/.local/share/nvim/mason/packages/typescript-language-server/node_modules/typescript/bin/tsserver'} }
tsserver = { cmd = {'your tsserver installed by lsp_installer'} }
}
})
```
example cmd setup (mac) for pyright :
```lua
```
require'navigator'.setup({
-- mason = false -- default value is false
-- lsp_installer = false -- default value is false
lsp = {
tsserver = {
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
-- or mason: cmd = { "/Users/username/.local/share/nvim/mason/packages/pyright/node_modules/pyright/index.js", "--stdio"}
}
}
}
```
### 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
* [neodev](https://github.com/folke/neodev.nvim) Dev setup for lua development. Navigator help you setup neodev
The lsp servers installed by nvim-lsp-installer is in following dir
* setup with neodev
```lua
use {"folke/neodev.nvim",
ft = 'lua',
config = function()
require'neodev'.setup{}
end
}
local path = require 'nvim-lsp-installer.path'
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
use {"ray-x/navigator.lua",
config=function()
require'navigator'.setup{}
end
}
```
* Here is an example to setup rust with rust-tools
And you can setup binary full path to this: (e.g. with gopls)
`install_root_dir .. '/go/gopls'` So the config is
```lua
require('rust-tools').setup({
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
local path = require 'nvim-lsp-installer.path'
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
require("navigator.dochighlight").documentHighlight(bufnr)
require('navigator.codeAction').code_action_prompt(bufnr)
-- otherwise, you can define your own commands to call navigator functions
end,
}
})
require'navigator'.setup({
-- lsp_installer = false -- default value is false
require("clangd_extensions").setup {
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
require("navigator.dochighlight").documentHighlight(bufnr)
require('navigator.codeAction').code_action_prompt(bufnr)
-- otherwise, you can define your own commands to call navigator functions
end,
lsp = {
gopls = {
cmd = { install_root_dir .. '/go/gopls' }
}
}
}
@ -759,14 +557,14 @@ e.g
require'navigator'.setup({on_attach = function(client, bufnr) require 'illuminate'.on_attach(client)})
```
## Highlighting
## Highlight
I am using:
Highlight I am using:
- LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()`
That is where you saw the current symbol been highlighted.
- GuihuaListDark and GuihuaTextViewDark is used for floating listvew and TextView. They are be based on current background
- GHListDark and GHTextViewDark is used for floating listvew and TextView. They are be based on current background
(Normal) and PmenuSel
- In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -775,19 +573,10 @@ You can override the above highlight to fit your current colorscheme
## commands
| command | function |
| --------------- | ------------------------------------------------------------------------- |
| LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP related keymaps |
| Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp |
| LspToggleFmt | toggle lsp format |
| LspSymbols | document symbol in side panel |
| LspAndDiag | document symbol and diagnostics in side panel |
| NRefPanel | show symbol reference in side panel |
| TSymbols | treesitter symbol in side panel |
| TsAndDiag | treesitter symbol and diagnostics in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incoming default), -o (outgoing) |
| command | function |
| ------------ | ------------------------- |
| LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP releated keymaps |
## Screenshots
@ -803,18 +592,6 @@ Using treesitter and LSP to view the symbol definition
![image](https://user-images.githubusercontent.com/1681295/139771978-bbc970a5-be9f-42cf-8942-3477485bd89c.png)
### Sidebar, folding, outline
Treesitter outline and Diagnostics
<img width="708" alt="image" src="https://user-images.githubusercontent.com/1681295/174791609-0023e68f-f1f4-4335-9ea2-d2360e9f0bfd.png">
<img width="733" alt="image" src="https://user-images.githubusercontent.com/1681295/174804579-26f87fbf-426b-46d0-a7a3-a5aab69c032f.png">
The side panel is vim buffer. You can toggle folds with za/zo/zc
Calltree (Expandable LSP call hierarchy)
<img width="769" alt="image" src="https://user-images.githubusercontent.com/1681295/176998572-e39fc968-4c8c-475d-b3b8-fb7991663646.png">
### GUI and multigrid support
You can load a different font size for floating win
@ -839,7 +616,7 @@ The key binding to navigate in the list.
![multiple_symbol_hi3](https://user-images.githubusercontent.com/1681295/120067627-f9f80680-c0bf-11eb-9216-18e5c8547f59.gif)
## Current symbol highlight and jump backward/forward between symbols
# Current symbol highlight and jump backward/forward between symbols
Document highlight provided by LSP.
Jump between symbols with treesitter (with `]r` and `[r`)
@ -864,9 +641,9 @@ Show diagnostic in all buffers
You can in place edit your code in floating window
<https://user-images.githubusercontent.com/1681295/121832919-89cbc080-cd0e-11eb-9778-11d0f356b38d.mov>
https://user-images.githubusercontent.com/1681295/121832919-89cbc080-cd0e-11eb-9778-11d0f356b38d.mov
(Note: This feature only available in `find reference` and `find diagnostic`, You can not add/remove lines in floating window)
(Note: This feature only avalible in `find reference` and `find diagnostic`, You can not add/remove lines in floating window)
### Implementation
@ -882,7 +659,7 @@ You can in place edit your code in floating window
### Symbol rename
<https://user-images.githubusercontent.com/1681295/200327179-0fc84660-44a8-4ee1-9631-2cc7a17b0b12.mov>
![rename](https://user-images.githubusercontent.com/1681295/141081135-55f45c2d-28c6-4475-a083-e37dfabe9afd.jpg)
#### Fill struct with gopls
@ -897,7 +674,15 @@ You can in place edit your code in floating window
Treetsitter symbols in all buffers
![treesitter](https://user-images.githubusercontent.com/1681295/118734953-cc6eba00-b882-11eb-9db8-0a052630d57e.jpg?raw=true)
### Call hierarchy (incoming/outgoing calls)
### Signature help
Improved signature help with current parameter highlighted
![signature](https://github.com/ray-x/files/blob/master/img/navigator/signature_with_highlight.jpg?raw=true)
![show_signature](https://github.com/ray-x/files/blob/master/img/navigator/show_signnature.gif?raw=true "show_signature")
### Call hierarchy (incomming/outgoing calls)
![incomming_calls](https://user-images.githubusercontent.com/1681295/142348079-49b71486-4f16-4f10-95c9-483aad11c262.jpg)
@ -919,44 +704,19 @@ Codelens for C++/ccls. Symbol reference
![nerdfont](https://github.com/ray-x/files/blob/master/img/navigator/icon_nerd.jpg?raw=true)
### Enhanced Folding Inspired by VS Code Using Treesitter
This feature introduces an advanced folding mechanism based on a customized variant of the treesitter folding algorithm (enabled with the ts_fold option).
#### function folding
### VS-code style folding with treesitter
The `end` delimiter of a function is recognized as a distinct
#### folding function
![image](https://user-images.githubusercontent.com/1681295/148491596-6cd6c507-c157-4536-b8c4-dc969436763a.png)
#### comments folding
Multiline comments are recognized as distinct blocks and can be collapsed seamlessly, simplifying navigation through extensive comments.
#### folding comments
![image](https://user-images.githubusercontent.com/1681295/148491845-5ffb18ea-f05d-4229-aec3-aa635b3de814.png)
#### Condition (if) block folding with syntax highlight
syntax highlight require treesitter and neovim 0.10 +
<img width="602" alt="image" src="https://user-images.githubusercontent.com/1681295/281574649-ecc911d3-bfe2-446a-9eb7-318600b37c30.png">
#### Function folding with syntax highlight
<img width="550" alt="image"
src="https://user-images.githubusercontent.com/1681295/281575203-3d08256a-7592-4bea-8e6a-c747023ff3a3.png">
### Signature help
Improved signature help with current parameter highlighted
# Debug the plugin
![signature](https://github.com/ray-x/files/blob/master/img/navigator/signature_with_highlight.jpg?raw=true)
![show_signature](https://github.com/ray-x/files/blob/master/img/navigator/show_signnature.gif?raw=true "show_signature")
## Debugging the plugin
One simple way to gather debug info and understand what is wrong is to output the debug logs
One simple way to gether debug info and understand what is wrong is output the debug logs
```lua
require'navigator'.setup({
@ -980,71 +740,21 @@ end
```
## Break changes and known issues
# Break changes and known issues
[known issues I am working on](https://github.com/ray-x/navigator.lua/issues/1)
## API and extensions
The plugin built on top of guihua, you can extend the plugin based on your requirements.
e.g. A side panel of lsp symbols and lsp diagnostics:
```lua
local function treesitter_and_diag_panel()
local Panel = require('guihua.panel')
local diag = require('navigator.diagnostics')
local ft = vim.bo.filetype
local results = diag.diagnostic_list[ft]
log(diag.diagnostic_list, ft)
local bufnr = api.nvim_get_current_buf()
local p = Panel:new({
header = 'treesitter',
render = function(b)
log('render for ', bufnr, b)
return require('navigator.treesitter').all_ts_nodes(b)
end,
})
p:add_section({
header = 'diagnostic',
render = function(buf)
log(buf, diagnostic)
if diag.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
```
## Todo
# Todo
- The project is in the early phase, bugs expected, PRs and suggestions are welcome
- Async (some of the requests is slow on large codebases and might be good to use co-rountine)
- More clients. I use go, python, js/ts, java, c/cpp, lua most of the time. Did not test other languages (e.g dart, swift etc)
- Configuration options
## Errors and Bug Reporting
# Errors and Bug Reporting
- Please double check your setup and check if minimum setup works or not
- It should works for 0.6.1, neovim 0.8.x preferred.
- 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.
- Check console output
- Check `LspInfo` and treesitter status with `checkhealth`
- Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log
- Submit Issue with minium init.lua. Please check playground/init.lua as a vimrc template.
Also check this repo [navigator bug report](https://github.com/fky2015/navigator.nvim-bug-report) on how to report bug
with minimum setup.

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

@ -1,11 +0,0 @@
# Change Logs
## 2023-12-07
- [x] Changed key maps
- Add fallback to key maps e.g. if `gD` does not find a type declaraion, it will fallback to `gD`
which is default key map go to global declaration
- `gt`: removed `gt` mapping and prefer `<space>D`
- [ ] Changed key maps
I plan to change the mapping for following key maps as it conflicts with other vim default key maps
- `gp`: changed to `<Leader>gp`
- `gP`: changed to `<Leader>gP`

@ -18,12 +18,10 @@ CONTENTS *navigator-content
5.4.1. LSP clients.................................|navigator-lsp_clients|
5.4.1.1. Add your own servers.........|navigator-add_your_own_servers|
5.4.2. Disable a lsp client loading from navigator.|navigator-disable_a_lsp_client_loading_from_navigator|
5.4.3. Try it your self.......................|navigator-try_it_your_self|
5.4.4. Default keymaps.........................|navigator-default_keymaps|
5.4.5. Colors/Highlight:.....................|navigator-colors/highlight:|
5.4.3. Default keymaps.........................|navigator-default_keymaps|
5.4.4. Colors/Highlight:.....................|navigator-colors/highlight:|
5.5. Dependency.........................................|navigator-dependency|
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.6. Integration with lsp_installer (williamboman/nvim-lsp-installer).|navigator-integration_with_lsp_installer_(williamboman/nvim-lsp-installer)|
5.7. Usage...................................................|navigator-usage|
5.8. Configuration...................................|navigator-configuration|
5.9. Highlight...........................................|navigator-highlight|
@ -31,11 +29,10 @@ CONTENTS *navigator-content
5.11. Screenshots......................................|navigator-screenshots|
5.11.1. Reference....................................|navigator-reference|
5.11.2. Definition preview..................|navigator-definition_preview|
5.11.3. Sidebar, folding, outline....|navigator-sidebar,_folding,_outline|
5.11.4. GUI and multigrid support....|navigator-gui_and_multigrid_support|
5.11.5. Document Symbol and navigate through the list.|navigator-document_symbol_and_navigate_through_the_list|
5.11.6. Workspace Symbol......................|navigator-workspace_symbol|
5.11.7. highlight document symbol and jump between reference.|navigator-highlight_document_symbol_and_jump_between_reference|
5.11.3. GUI and multigrid support....|navigator-gui_and_multigrid_support|
5.11.4. Document Symbol........................|navigator-document_symbol|
5.11.5. Workspace Symbol......................|navigator-workspace_symbol|
5.11.6. highlight document symbol and jump between reference.|navigator-highlight_document_symbol_and_jump_between_reference|
6. Current symbol highlight and jump backward/forward between symbols.|navigator-current_symbol_highlight_and_jump_backward/forward_between_symbols|
6.1. Diagnostic.....................................|navigator-diagnostic|
6.2. Edit in preview window.............|navigator-edit_in_preview_window|
@ -51,9 +48,6 @@ CONTENTS *navigator-content
6.11. Light bulb if codeAction available.|navigator-light_bulb_if_codeaction_available|
6.12. Codelens........................................|navigator-codelens|
6.13. Predefined LSP symbol nerdfont/emoji.|navigator-predefined_lsp_symbol_nerdfont/emoji|
6.14. VS-code style folding with treesitter.|navigator-vs-code_style_folding_with_treesitter|
6.14.1. folding function..................|navigator-folding_function|
6.14.2. folding comments..................|navigator-folding_comments|
7. Debug the plugin...................................|navigator-debug_the_plugin|
8. Break changes and known issues.......|navigator-break_changes_and_known_issues|
9. Todo...........................................................|navigator-todo|
@ -62,14 +56,8 @@ CONTENTS *navigator-content
================================================================================
NAVIGATOR *navigator-navigator*
* Source code analysis and navigate tool
* Easy code navigation, view diagnostic errors, see relationships of functions, variables
* A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively.
* ctags fuzzy search & build ctags symbols
-
* [](https://youtu.be/P1kd7Y8AatE)
Here are some examples
@ -126,7 +114,7 @@ FEATURES: *navigator-features
* Luv async thread and tasks
* Edit your code in preview window
* Async request with lsp.buf_request for reference search
* Treesitter symbol search. It is handy for large files (Some of LSP e.g. lua_ls, there is a 100kb file size limitation?)
* Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limitation?)
* FZY search with either native C (if gcc installed) or Lua-JIT
* LSP multiple symbol highlight/marker and hop between document references
* Preview definination/references
@ -139,8 +127,7 @@ FEATURES: *navigator-features
* Optimize display (remove trailing bracket/space), display the caller of reference, de-duplicate lsp results (e.g reference
in the same line). Using treesitter for file preview highlighter etc
* ccls call hierarchy (Non-standard `ccls/call` API) supports
* Syntax folding based on treesitter 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
* Syntax folding based on treesitter folding algorithm. (It behaves similar to vs-code)
* Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
* LRU cache for treesitter nodes
* Lazy loader friendly
@ -164,7 +151,7 @@ SIMILAR PROJECTS / SPECIAL MENTIONS: *navigator-similar_projects_/_special_menti
================================================================================
INSTALL *navigator-install*
Require nvim-0.6.1 or above, nightly (0.8) prefered
Require nvim-0.5.0 (a.k.a nightly)
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)).
@ -174,17 +161,11 @@ The plugin depends on lspconfig and guihua.lua (https://github.com/ray-x/guihua.
Plug 'ray-x/navigator.lua'
<
Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
Note: Highly recommened: 'nvim-treesitter/nvim-treesitter'
Packer
>
use({
'ray-x/navigator.lua',
requires = {
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
{ 'neovim/nvim-lspconfig' },
},
})
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}}
<
--------------------------------------------------------------------------------
@ -202,11 +183,11 @@ SAMPLE VIMRC TURNING YOUR NEOVIM INTO A FULL-FEATURED IDE *navigator-sample_vimr
Plug 'neovim/nvim-lspconfig'
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
Plug 'ray-x/navigator.lua'
" Plug 'hrsh7th/nvim-cmp' and other plugins you commenly use...
" Plug 'hrsh7th/nvim-compe' and other plugins you commenly use...
" optional, if you need treesitter symbol support
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
call plug#end()
" No need for require('lspconfig'), navigator will configure it for you
" No need for rquire('lspconfig'), navigator will configure it for you
lua <<EOF
require'navigator'.setup()
EOF
@ -257,7 +238,7 @@ ALL CONFIGURE OPTIONS *navigator-all_configure_option
Nondefault configuration example:
>
require'navigator'.setup({
debug = false, -- log output, set to true and log path: ~/.cache/nvim/gh.log
debug = false, -- 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
@ -277,9 +258,6 @@ Nondefault configuration example:
-- please check mapping.lua for all keymaps
treesitter_analysis = true, -- treesitter variable context
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- setup here. if it is nil, navigator will not init signature help
signature_help_cfg = nil, -- if you would like to init ray-x/lsp_signature plugin in navigator, and pass in your own config to signature help
icons = {
-- Code action
code_action_icon = "🏏",
@ -290,51 +268,25 @@ Nondefault configuration example:
},
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
lsp = {
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
-- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
code_lens_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
format_on_save = true, -- {true|false} set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
-- table: {enable = {'lua', 'go'}, disable = {'javascript', 'typescript'}} to enable/disable specific language
-- enable: a whitelist of language that will be formatted on save
-- disable: a blacklist of language that will not be formatted on save
-- function: function(bufnr) return true end to enable/disable lsp format on save
disable_format_cap = {"sqlls", "lua_ls", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
format_on_save = true, -- set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
disable_format_cap = {"sqls", "sumneko_lua", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
disable_lsp = {'pylsd', 'sqlls'}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
-- only want to enable one lsp server
-- to disable all default config and use your own lsp setup set
-- disable_lsp = 'all'
-- Default {}
diagnostic = {
underline = true,
virtual_text = true, -- show virtual for diagnostic message
update_in_insert = false, -- update diagnostic message in insert mode
float = {
focusable = false,
style = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
}
},
diagnostic_scrollbar_sign = {'▃', '▆', '█'}, -- experimental: diagnostic status in scroll bar area; set to false to disable the diagnostic sign,
-- for other style, set to {'╍', 'ﮆ'} or {'-', '='}
diagnostic_virtual_text = true, -- show virtual for diagnostic message
diagnostic_update_in_insert = false, -- update diagnostic message in insert mode
display_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to
disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to
ignore it
tsserver = {
filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetypes
},
ctags ={
cmd = 'ctags',
tagfile = 'tags'
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number'
}
gopls = { -- gopls setting
on_attach = function(client, bufnr) -- on_attach for gopls
-- your special on attach here
@ -346,12 +298,11 @@ Nondefault configuration example:
gopls = {gofumpt = false} -- disable gofumpt etc,
}
},
lua_ls = {
sumneko_lua = {
sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server",
sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
},
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
servers = {'cmake', 'ltex'}, -- by default empty, but if you whant navigator load e.g. `cmake` and `ltex` for you , you
-- can put them in the `servers` list and navigator will auto load them.
-- you could still specify the custom config like this
-- cmake = {filetypes = {'cmake', 'makefile'}, single_file_support = false},
@ -365,11 +316,10 @@ Built clients:
>
local servers = {
"angularls", "gopls", "tsserver", "flow", "bashls", "dockerls", "julials", "pylsp", "pyright",
"jedi_language_server", "jdtls", "lua_ls", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqlls", "denols", "graphql", "dartls", "dotls",
"jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls",
"kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp",
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls",
"sourcekit", "fsautocomplete", "vls", "hls"
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp"
}
<
@ -382,14 +332,14 @@ Other than above setup, additional none default setup are used for following lsp
* gopls
* clangd
* rust_analyzer
* sqlls
* lua_ls
* sqls
* sumneko_lua
* pyright
* ccls
Please check client setup (https://github.com/ray-x/navigator.lua/blob/26012cf9c172aa788a2e53018d94b32c5c75af75/lua/navigator/lspclient/clients.lua#L98-L234)
The plugin can work with multiple LSP, e.g sqlls+gopls+efm. But there are cases you may need to disable some of the
The plugin can work with multiple LSP, e.g sqls+gopls+efm. But there are cases you may need to disable some of the
servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use
pylsp+pyright+jedi
together. If you have multiple similar LSP installed and have trouble with the plugin, please enable only one at a time.
@ -399,12 +349,12 @@ ADD YOUR OWN SERVERS *navigator-add_your_own_server
Above servers covered a small part neovim lspconfig support, You can still use lspconfig to add and config servers not
in the list. If you would like to add a server not in the list, you can check this PR https://github.com/ray-x/navigator.lua/pull/107
Alternatively, update following option in setup(if you do not want a PR):
Also, an option in setup:
>
require'navigator'setup{lsp={servers={'cmake', 'lexls'}}}
<
Above option add cmake and lexls to the default server list
Above example add cmake and lexls to the default server list
DISABLE A LSP CLIENT LOADING FROM NAVIGATOR *navigator-disable_a_lsp_client_loading_from_navigator*
@ -427,16 +377,11 @@ Or:
})
<
TRY IT YOUR SELF *navigator-try_it_your_self*
In `playground` folder, there is a `init.lua` and source code for you to play with. Check playground/README.md (https://github.com/ray-x/navigator.lua/blob/master/playground/README.md) for more details
DEFAULT KEYMAPS *navigator-default_keymaps*
| mode | key | function |
| ---- | --------------- | ---------------------------------------------------------- |
| n | gr | async references, definitions and context |
| n | <Leader>gr | show reference and context |
| n | gr | show reference and context |
| i | <m-k> | signature help |
| n | <c-k> | signature help |
| n | gW | workspace symbol |
@ -447,20 +392,18 @@ DEFAULT KEYMAPS *navigator-default_keymap
| n | gp | definition preview (Go to Preview) |
| n | <C-LeftMouse> | definition |
| n | g<LeftMouse> | implementation |
| n | <Leader>gt | treesitter document symbol |
| n | gT | treesitter document symbol |
| n | <Leader>gT | treesitter symbol for all open buffers |
| n | <Leader> ct | ctags symbol search |
| n | <Leader> cg | ctags symbol generate |
| n | K | hover doc |
| n | <Space>ca | code action (when you see 🏏 ) |
| n | <Space>la | code lens action (when you see a codelens indicator) |
| v | <Space>ca | range code action (when you see 🏏 ) |
| v | <Space>cA | range code action (when you see 🏏 ) |
| n | <Space>rn | rename with floating window |
| n | <Leader>re | rename (lsp default) |
| n | <Leader>gi | hierarchy incoming calls |
| n | <Leader>go | hierarchy outgoing calls |
| n | gi | implementation |
| n | <Space> D | type definition |
| n | <Sapce> D | type definition |
| n | gL | show line diagnostic |
| n | gG | show diagnostic for all buffers |
| n | ]d | next diagnostic |
@ -468,9 +411,9 @@ DEFAULT KEYMAPS *navigator-default_keymap
| n | <Leader> dt | diagnostic toggle(enable/disable) |
| n | ]r | next treesitter reference/usage |
| n | [r | previous treesitter reference/usage |
| n | <Space> wa | add workspace folder |
| n | <Space> wr | remove workspace folder |
| n | <Space> wl | print workspace folder |
| n | <Sapce> wa | add workspace folder |
| n | <Sapce> wr | remove workspace folder |
| n | <Sapce> wl | print workspace folder |
| n | <Leader>k | toggle reference highlight |
| i/n | <C-p> | previous item in list |
| i/n | <C-n> | next item in list |
@ -491,13 +434,13 @@ DEFAULT KEYMAPS *navigator-default_keymap
COLORS/HIGHLIGHT: *navigator-colors/highlight:*
You can override default highlight GuihuaListDark (listview) and GuihuaTextViewDark (code view) and GuihuaListHl (select item)
You can override default highlight GHListDark (listview) and GHTextViewDark (code view) and GHListHl (select item)
e.g.
>
hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GuihuaListHl guifg=#e0d8f4 guibg=#404254
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254
<
There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -517,43 +460,19 @@ The plugin can be loaded lazily (packer `opt = true` ), And it will check if opt
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
--------------------------------------------------------------------------------
INTEGRAT WITH LSP_INSTALLER (WILLIAMBOMAN/NVIM-LSP-INSTALLER) *navigator-integrat_with_lsp_installer_(williamboman/nvim-lsp-installer)*
INTEGRATION WITH LSP_INSTALLER (WILLIAMBOMAN/NVIM-LSP-INSTALLER) *navigator-integration_with_lsp_installer_(williamboman/nvim-lsp-installer)*
If you are using lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
If you'd like to only use the lsp servers installed by lsp_installer. Please set
>
lsp_installer = true
<
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,
})
<
Please refer to lsp_installer_config (https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
for more info
In the config.
Alternatively, Navigator can be used to startup the server installed by lsp-installer.
Navigator will startup the server installed by lsp-installer. Please do not call `server:setup{opts}` from lsp installer
as it will override the navigator setup
To start LSP installed by lsp_installer, please use following setups
Also, could use following setups
>
require'navigator'.setup({
-- lsp_installer = false -- default value is false
@ -565,70 +484,7 @@ To start LSP installed by lsp_installer, please use following setups
example cmd setup (mac) for pyright :
>
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,
}
}
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
<
--------------------------------------------------------------------------------
@ -658,7 +514,7 @@ Highlight I am using:
* LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()`
That is where you saw the current symbol been highlighted.
* GuihuaListDark and GuihuaTextViewDark is used for floating listvew and TextView. They are be based on current background
* GHListDark and GHTextViewDark is used for floating listvew and TextView. They are be based on current background
(Normal) and PmenuSel
* In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -667,45 +523,10 @@ You can override the above highlight to fit your current colorscheme
--------------------------------------------------------------------------------
COMMANDS *navigator-commands*
| command | function |
| ------------ | ------------------------- |
| LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP releated keymaps |
| Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp |
| LspSymbols | document symbol in side panel |
| NRefPanel |symbol reference in side panel |
| TSymobls | treesitter symbol in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
:LspToggleFmt *:LspToggleFmt*
Toggle lsp auto format.
:LspKeymaps *:LspKeymaps*
Show Lsp keymaps.
:Nctags [flags] *:Nctags*
Show ctags symbols.
[flags]:
-g regen ctags
:LspRestart *:LspRestart*
Restart Lsp.
:LspSymbols *:LspSymbols*
Lsp document symbol in side panel.
:TSSymbols *:TSSymbols*
Treesitter symbol in side panel.
:NRefPanel *:NRefPanel*
Symbol reference in side panel.
:Calltree [flags] *:Calltree*
Lsp call hierarchy call tree.
[flags]:
-i: incomming default
-o: outgoing
| command | function |
| ------------ | ---------------------- |
| LspToggleFmt | toggle lsp auto format |
--------------------------------------------------------------------------------
SCREENSHOTS *navigator-screenshots*
@ -721,27 +542,15 @@ Using treesitter and LSP to view the symbol definition
SIDEBAR, FOLDING, OUTLINE *navigator-sidebar,_folding,_outline*
Treesitter outline and Diagnostics
GUI AND MULTIGRID SUPPORT *navigator-gui_and_multigrid_support*
You can load a different font size for floating win
DOCUMENT SYMBOL AND NAVIGATE THROUGH THE LIST *navigator-document_symbol_and_navigate_through_the_list*
DOCUMENT SYMBOL *navigator-document_symbol*
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*
@ -840,16 +649,6 @@ 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*
@ -888,10 +687,8 @@ TODO *navigator-tod
ERRORS AND BUG REPORTING *navigator-errors_and_bug_reporting*
* Please double check your setup and check if minium setup works or not
* It should works for 0.6.1, neovim 0.7.x prefered.
* It should works for 0.5.1, neovim 0.6.x prefered.
* Check console output
* Check `LspInfo` and treesitter status with `checkhealth`
* Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log
* Submit Issue with minium vimrc. Please check playground/init.lua as a vimrc template. !!!Please DONOT use a packer vimrc
that installs everything to default folder!!! Also check this repo navigator bug report (https://github.com/fky2015/navigator.nvim-bug-report)

@ -1,4 +0,0 @@
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

@ -1,75 +1,47 @@
local M = {}
local api = vim.api
local function warn(msg)
api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
vim.api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
end
local function info(msg)
if _NgConfigValues.debug then
api.nvim_echo({ { 'Debug: ' .. msg } }, true, {})
end
vim.api.nvim_echo({ { 'Info: ' .. msg } }, true, {})
end
_NgConfigValues = {
debug = false, -- log output
width = 0.75, -- value of cols
width = 0.62, -- valeu of cols
height = 0.38, -- listview height
preview_height = 0.38,
preview_lines = 40, -- total lines in preview screen
preview_lines_before = 5, -- lines before the highlight line
default_mapping = true,
keymaps = {}, -- e.g keymaps={{key = "GR", func = vim.lsp.buf.references}, } this replace gr default mapping
keymaps = {}, -- e.g keymaps={{key = "GR", func = "references()"}, } this replace gr default mapping
external = nil, -- true: enable for goneovim multigrid otherwise false
border = 'single', -- border style, can be one of 'none', 'single', 'double', "shadow"
lines_show_prompt = 10, -- when the result list items number more than lines_show_prompt,
prompt_mode = 'insert', -- 'normal' | 'insert'
-- fuzzy finder prompt will be shown
combined_attach = 'both', -- both: use both customized attach and navigator default attach, mine: only use my attach defined in vimrc
on_attach = function(client, bufnr)
-- your on_attach will be called at end of navigator on_attach
end,
-- ts_fold = false, -- deprecated
ts_fold = {
enable = false,
comment = true, -- ts fold text object
max_lines_scan_comments = 2000, -- maximum lines to scan for comments
disable_filetypes = { 'help', 'text', 'markdown' }, -- disable ts fold for specific filetypes
},
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_navigation = true, -- bool|table
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_max_fnum = 20, -- how many files to run treesitter analysis
treesitter_analysis_condense = true, -- short format of function
treesitter_analysis_depth = 3, -- max depth
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- setup here. if it is nil, navigator will not init signature help
signature_help_cfg = { debug = false }, -- if you would like to init ray-x/lsp_signature plugin in navigator, pass in signature help
ctags = {
cmd = 'ctags',
tagfile = '.tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
signature_help_cfg = {debug=false}, -- if you would like to init ray-x/lsp_signature plugin in navigator, pass in signature help
lsp = {
enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach
code_action = {
delay = 3000, -- how long the virtual text will be shown
enable = true,
sign = true,
sign_priority = 40,
virtual_text = true,
virtual_text_icon = true,
},
rename = {
enable = true,
style = 'floating-preview', -- 'floating' | 'floating-preview' | 'inplace-preview'
show_result = true,
confirm = '<S-CR>',
cancel = '<S-ESC>',
},
document_highlight = true, -- highlight reference a symbol
code_lens_action = {
enable = true,
sign = true,
@ -77,77 +49,12 @@ _NgConfigValues = {
virtual_text = true,
virtual_text_icon = true,
},
diagnostic = {
enable = true,
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 },
float = {
focusable = false,
sytle = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
},
definition = { enable = true },
call_hierarchy = { enable = true },
implementation = { enable = true },
workspace = { enable = true },
hover = {
enable = true,
keymaps = {
['<C-k>'] = {
go = function()
local w = vim.fn.expand('<cWORD>')
w = w:gsub('*', '')
vim.cmd('GoDoc ' .. w)
end,
python = function()
local w = vim.fn.expand('<cWORD>')
local setup = {
'pydoc',
w,
}
return vim.fn.jobstart(setup, {
on_stdout = function(_, data, _)
if not data or (#data == 1 and vim.fn.empty(data[1]) == 1) then
return
end
local close_events = { 'CursorMoved', 'CursorMovedI', 'BufHidden', 'InsertCharPre' }
local config = {
close_events = close_events,
focusable = true,
border = 'single',
width = 80,
zindex = 100,
}
vim.lsp.util.open_floating_preview(data, 'python', config)
end,
})
end,
default = function()
local w = vim.fn.expand('<cword>')
print('default ' .. w)
vim.lsp.buf.workspace_symbol(w)
end,
},
},
}, -- bind hover action to keymap; there are other options e.g. noice, lspsaga provides lsp hover
format_on_save = true, -- {true|false} set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
-- table: {enable = {'lua', 'go'}, disable = {'javascript', 'typescript'}} to enable/disable specific language
-- enable: a whitelist of language that will be formatted on save
-- disable: a blacklist of language that will not be formatted on save
-- function: function(bufnr) return true end to enable/disable lsp format on save
format_options = { async = false }, -- async: disable by default, I saw something unexpected
disable_nulls_codeaction_sign = true, -- do not show nulls codeactions (as it will alway has a valid action)
format_on_save = true, -- set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
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
code_lens = false,
-- only want to enable one lsp server
display_diagnostic_qf = false, -- bool: always show quickfix if there are diagnostic errors
-- string: trouble use trouble to show diagnostic
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
-- to load those files
diagnostic_virtual_text = true, -- show virtual for diagnostic message
@ -157,94 +64,71 @@ _NgConfigValues = {
-- filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetype
},
neodev = false,
lua_ls = {
sumneko_lua = {
-- sumneko_root_path = sumneko_root_path,
-- sumneko_binary = sumneko_binary,
-- cmd = {'lua-language-server'}
},
servers = {}, -- you can add additional lsp server so navigator will load the default for you
},
mason = false, -- set to true if you would like use the lsp installed by williamboman/mason
mason_disabled_for = {}, -- disable mason for specified lspclients
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
icons = {
-- requires Nerd Font or nvim-web-devicons pre-installed
icons = true, -- set to false to use system default ( if you using a terminal does not have nerd/icon)
-- Code Action (gutter, floating window)
code_action_icon = '🏏',
-- Code Lens (gutter, floating window)
-- Code action
code_action_icon = '🏏', -- "",
-- code lens
code_lens_action_icon = '👓',
-- Diagnostics (gutter)
diagnostic_head = '🐛', -- prefix for other diagnostic_* icons
-- Diagnostics
diagnostic_head = '🐛',
diagnostic_err = '📛',
diagnostic_warn = '👎',
diagnostic_info = [[👩]],
diagnostic_hint = [[💁]],
-- Diagnostics (floating window)
diagnostic_head_severity_1 = '🈲',
diagnostic_head_severity_2 = '🛠️',
diagnostic_head_severity_3 = '🔧',
diagnostic_head_description = '👹', -- suffix for severities
diagnostic_virtual_text = '🦊', -- floating text preview (set to empty to disable)
diagnostic_file = '🚑', -- icon in floating window, indicates the file contains diagnostics
-- Values (floating window)
value_definition = '🐶🍡', -- identifier defined
value_changed = '📝', -- identifier modified
context_separator = '', -- separator between text and value
-- Formatting for Side Panel
side_panel = {
section_separator = '󰇜',
line_num_left = '',
line_num_right = '',
inner_node = '├○',
outer_node = '╰○',
bracket_left = '',
bracket_right = '',
tab = '󰌒',
},
fold = {
prefix = '',
separator = '',
},
diagnostic_head_severity_2 = '☣️',
diagnostic_head_severity_3 = '👎',
diagnostic_head_description = '👹',
diagnostic_virtual_text = '🦊',
diagnostic_file = '🚑',
-- Values
value_changed = '📝',
value_definition = '🐶🍡', -- it is easier to see than 🦕
-- Treesitter
-- Note: many more node.type or kind may be available
match_kinds = {
var = '', -- variable -- "👹", -- Vampaire
const = '󱀍 ',
method = 'ƒ ', -- method -- "🍔", -- mac
-- function is a keyword so wrap in ['key'] syntax
['function'] = '󰡱 ', -- function -- "🤣", -- Fun
parameter = '', -- param/arg -- Pi
parameters = '', -- param/arg -- Pi
required_parameter = '', -- param/arg -- Pi
associated = '🤝', -- linked/related
namespace = '🚀', -- namespace
type = '󰉿', -- type definition
field = '🏈', -- field definition
module = '📦', -- module
flag = '🎏', -- flag
var = '', -- "👹", -- Vampaire
method = 'ƒ ', -- "🍔", -- mac
['function'] = '', -- "🤣", -- Fun
parameter = '', -- Pi
associated = '🤝',
namespace = '🚀',
type = '',
field = '🏈',
},
treesitter_defult = '🌲', -- default symbol when unknown node.type or kind
doc_symbols = '', -- document
treesitter_defult = '🌲',
},
}
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)
if cfg.ts_fold ~= nil and type(cfg.ts_fold) == 'boolean' then
warn('ts_fold option changed, refer to README for more details')
cfg.ts_fold = { enable = cfg.ts_fold }
local warn = require('navigator.util').warn
if cfg.code_action_prompt then
warn('code_action_prompt moved to lsp.code_action')
end
local has_nvim_010 = vim.fn.has('nvim-0.10') == 1
if not has_nvim_010 then
vim.lsp.get_clients = vim.lsp.get_active_clients
vim.islist = vim.tbl_islist
if cfg.code_lens_action_prompt then
warn('code_lens_action_prompt moved to lsp.code_lens_action')
end
if cfg.lsp ~= nil and cfg.lsp.disable_format_ft ~= nil and cfg.lsp.disable_format_ft ~= {} then
warn('disable_format_ft renamed to disable_format_cap')
end
if cfg.lspinstall ~= nil then
warn('lspinstall deprecated, please use lsp-installer instead or use "lspinstall" branch')
end
end
@ -253,18 +137,15 @@ local extend_config = function(opts)
if next(opts) == nil then
return
end
if opts.debug then
_NgConfigValues.debug = opts.debug
if opts.lsp and opts.lsp.servers then
require('navigator.lspclient.clients').add_servers(opts.lsp.servers)
opts.lsp.server = nil
end
-- enable logs
require('navigator.util').setup()
M.deprecated(opts)
for key, value in pairs(opts) do
if _NgConfigValues[key] == nil then
warn(
string.format(
'[󰎐] Deprecated? Key %s is not in default setup, it could be incorrect to set to %s',
'[] Deprecated? Key %s is not in default setup, it could be incorrect to set to %s',
key,
vim.inspect(value)
)
@ -276,7 +157,7 @@ local extend_config = function(opts)
if type(value) ~= 'table' then
info(
string.format(
'[󰎐] Reset type: Key %s setup value %s type %s , from %s',
'[] Reset type: Key %s setup value %s type %s , from %s',
key,
vim.inspect(value),
type(value),
@ -302,17 +183,15 @@ local extend_config = function(opts)
else
if _NgConfigValues[key][k] == nil then
if key == 'lsp' then
local lsp = require('navigator.lspclient.servers')
-- if not vim.tbl_contains(lsp or {}, k) and k ~= 'efm' and k ~= 'null-ls' then
-- info(string.format('[󰎐] extend LSP support for %s %s ', key, k))
-- end
elseif key == 'signature_help_cfg' then
_NgConfigValues[key][k] = v
local lsp = require('navigator.lspclient.clients').lsp
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))
end
elseif key == 'keymaps' then
info('keymap override' .. vim.inspect(v))
info('keymap override')
-- skip key check and allow mapping to handle that
else
warn(string.format('[󰎐] Key %s %s not valid', key, k))
warn(string.format('[] Key %s %s not valid', key, k))
end
-- return
end
@ -324,81 +203,43 @@ local extend_config = function(opts)
end
end
end
-- if _NgConfigValues.sumneko_root_path or _NgConfigValues.sumneko_binary then
-- vim.notify("Please put sumneko setup in lsp['lua_ls']", vim.log.levels.WARN)
-- end
if _NgConfigValues.sumneko_root_path or _NgConfigValues.sumneko_binary then
vim.notify("Please put sumneko setup in lsp['sumneko_lua']", vim.log.levels.WARN)
end
M.deprecated(opts)
end
M.config_values = function()
return _NgConfigValues
end
local cmd_group
M.setup = function(cfg)
cfg = cfg or {}
extend_config(cfg)
if not cmd_group then
cmd_group = api.nvim_create_augroup('NGFtGroup', {})
api.nvim_create_autocmd({ 'FileType', 'BufEnter' }, {
group = cmd_group,
pattern = '*',
callback = function()
require('navigator.lspclient.clients').on_filetype()
end,
})
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.lspclient.clients').setup(_NgConfigValues)
-- require("navigator.lspclient.mapping").setup(_NgConfigValues)
require('navigator.reference')
require('navigator.definition')
require('navigator.hierarchy')
require('navigator.implementation')
-- log("navigator loader")
-- vim.cmd("autocmd BufNewFile,BufRead *.go setlocal noexpandtab tabstop=4 shiftwidth=4")
if not _NgConfigValues.loaded then
_NgConfigValues.loaded = true
end
vim.defer_fn(function()
require('navigator.lazyloader').init()
require('navigator.lspclient.clients').setup(_NgConfigValues)
require('navigator.reference')
require('navigator.definition')
require('navigator.hierarchy')
require('navigator.implementation')
local ts_installed = pcall(require, 'nvim-treesitter')
if not ts_installed then
if _NgConfigValues.ts_fold.enable == true then
warn('treesitter not installed ts_fold disabled')
_NgConfigValues.ts_fold.enable = false
end
if _NgConfigValues.treesitter_analysis == true then
warn('nvim-treesitter not installed, disable treesitter_analysis')
_NgConfigValues.treesitter_analysis = false
end
if _NgConfigValues.treesitter_navigation == true then
warn('nvim-treesitter not installed, disable treesitter_navigation')
_NgConfigValues.treesitter_navigation = false
end
end
cfg.lsp = cfg.lsp or _NgConfigValues.lsp
if _NgConfigValues.lsp.enable then
require('navigator.diagnostics').config(cfg.lsp.diagnostic)
end
if not _NgConfigValues.loaded then
_NgConfigValues.loaded = true
end
if
_NgConfigValues.ts_fold.enable == true
and not vim.tbl_contains(_NgConfigValues.ts_fold.disable_filetypes, vim.o.filetype)
and not vim.wo.diff
then
require('navigator.foldts').on_attach()
end
local _start_client = vim.lsp.start_client
vim.lsp.start_client = function(lsp_config)
-- add highlight for Lspxxx
require('navigator.lspclient.highlight').add_highlight()
require('navigator.lspclient.highlight').config_signs()
-- require('navigator.lspclient.mapping').setup()
require('navigator.lspclient.lspkind').init()
return _start_client(lsp_config)
end
end, 1)
if _NgConfigValues.ts_fold == true then
require('navigator.foldts').on_attach()
end
end
return M

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

@ -2,7 +2,7 @@ local util = require('navigator.util')
local log = util.log
local trace = util.trace
local code_action = {}
-- local gui = require('navigator.gui')
local gui = require('navigator.gui')
local config = require('navigator').config_values()
local api = vim.api
@ -27,8 +27,6 @@ end
local function _update_virtual_text(line, actions)
local namespace = get_namespace()
pcall(api.nvim_buf_clear_namespace, 0, namespace, 0, -1)
local bufnr = api.nvim_get_current_buf()
api.nvim_buf_del_extmark(bufnr, namespace, 1)
if line then
trace(line, actions)
@ -36,7 +34,8 @@ local function _update_virtual_text(line, actions)
local title = actions[1].title
pcall(api.nvim_buf_set_extmark, 0, namespace, line, -1, {
virt_text = { { icon_with_indent .. title, 'DiagnosticsSignHint' } },
virt_text = { { icon_with_indent .. title, 'LspDiagnosticsSignHint' } },
virt_text_pos = 'overlay',
hl_mode = 'combine',
})
end
@ -46,31 +45,27 @@ local function _update_sign(line)
if vim.tbl_isempty(vim.fn.sign_getdefined(sign_name)) then
vim.fn.sign_define(sign_name, {
text = config.icons.code_action_icon,
texthl = 'DiagnosticsSignHint',
texthl = 'LspDiagnosticsSignHint',
})
end
local winid = get_current_winid()
if code_action[winid] == nil then
code_action[winid] = {}
end
-- 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
if code_action[winid].lightbulb_line ~= 0 then
vim.fn.sign_unplace(sign_group, { id = code_action[winid].lightbulb_line, buffer = '%' })
trace('sign removed', line)
end
if line then
-- log("updatasign", line, sign_group, sign_name)
local id = vim.fn.sign_place(
vim.fn.sign_place(
line,
sign_group,
sign_name,
'%',
{ lnum = line + 1, priority = config.lsp.code_action.sign_priority }
)
code_action[winid].lightbulb_line = id
log('sign updated', id, line, sign_group, sign_name)
code_action[winid].lightbulb_line = line
end
end
@ -79,14 +74,6 @@ local need_check_diagnostic = { ['python'] = true }
function code_action:render_action_virtual_text(line, diagnostics)
return function(err, actions, context)
trace(actions, context)
if context and context.client_id then
local cname = vim.lsp.get_clients({ id = context.client_id })[1].name
if cname == 'null-ls' and _NgConfigValues.lsp.disable_nulls_codeaction_sign then
return
end
end
-- if nul-ls enabled, some of the lsp may not send valid code action,
if actions == nil or type(actions) ~= 'table' or vim.tbl_isempty(actions) then
-- no actions cleanup
if config.lsp.code_action.virtual_text then
@ -97,13 +84,12 @@ function code_action:render_action_virtual_text(line, diagnostics)
end
else
trace(err, line, diagnostics, actions, context)
if config.lsp.code_action.sign then
if need_check_diagnostic[vim.bo.filetype] then
if next(diagnostics) == nil then
-- no diagnostic, no code action sign..
_update_sign(nil)
else
-- no diagnostic, no code action sign..
_update_sign(line)
end
else
@ -111,25 +97,18 @@ function code_action:render_action_virtual_text(line, diagnostics)
end
end
if not config.lsp.code_action.virtual_text then
return
end
if need_check_diagnostic[vim.bo.filetype] and not next(diagnostics) then
_update_virtual_text()
else
_update_virtual_text(line, actions)
end
end
vim.defer_fn(function()
trace('clear vt')
if config.lsp.code_action.virtual_text then
_update_virtual_text(nil)
end
if config.lsp.code_action.sign then
_update_sign(nil)
if need_check_diagnostic[vim.bo.filetype] then
if next(diagnostics) == nil then
_update_virtual_text(nil)
else
_update_virtual_text(line, actions)
end
else
_update_virtual_text(line, actions)
end
end
end, _NgConfigValues.lsp.code_action.delay)
end
end
end
@ -142,6 +121,9 @@ local special_buffers = {
['markdown'] = true,
['text'] = true,
}
-- local action_call_back = function (_,_)
-- return Action:action_callback()
-- end
local action_virtual_call_back = function(line, diagnostics)
return code_action:render_action_virtual_text(line, diagnostics)
@ -156,21 +138,11 @@ local code_action_req = function(_call_back_fn, diagnostics)
vim.lsp.buf_request(0, 'textDocument/codeAction', params, callback)
end
local function sort_select(action_tuples, opts, on_user_choice)
if action_tuples ~= nil and action_tuples[1][2] ~= nil and action_tuples[1][2].command then
table.sort(action_tuples, function(a, b)
return a[1] > b[1]
end)
end
opts.width = config.width
trace(action_tuples)
require('guihua.gui').select(action_tuples, opts, on_user_choice)
end
code_action.code_action = function()
local original_select = vim.ui.select
vim.ui.select = sort_select
vim.ui.select = require('guihua.gui').select
log('codeaction')
vim.lsp.buf.code_action()
vim.defer_fn(function()
@ -181,29 +153,19 @@ end
code_action.range_code_action = function(startpos, endpos)
local context = {}
context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
local params = util.make_given_range_params(startpos, endpos)
params.context = context
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 original_select = vim.ui.select
vim.ui.select = require('guihua.gui').select
local original_input = vim.ui.input
vim.ui.input = require('guihua.input').input
if vim.fn.has('nvim-0.8') then
vim.lsp.buf.code_action({ context = context, range = { start = startpos, ['end'] = endpos } })
else
vim.lsp.buf.range_code_action(context, startpos, endpos)
end
vim.lsp.buf.range_code_action(context, startpos, endpos)
vim.defer_fn(function()
vim.ui.select = original_select
vim.ui.input = original_input
end, 1000)
end
code_action.code_action_prompt = function(bufnr)
code_action.code_action_prompt = function()
if special_buffers[vim.bo.filetype] then
log('skip buffer', vim.bo.filetype)
return

@ -4,13 +4,15 @@
local codelens = require('vim.lsp.codelens')
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
-- trace = log
local lsphelper = require('navigator.lspwrapper')
local api = vim.api
local gui = require('navigator.gui')
local M = {}
M.disabled = {}
local config = require('navigator').config_values()
local sign_name = 'NavigatorCodeLensLightBulb'
if vim.tbl_isempty(vim.fn.sign_getdefined(sign_name)) then
@ -47,8 +49,8 @@ local function _update_sign(line)
end
end
local codelens_hdlr = function(err, result, ctx, cfg)
trace(ctx, result)
local codelens_hdlr = mk_handler(function(err, result, ctx, cfg)
log(ctx, result)
M.codelens_ctx = ctx
if err or result == nil then
if err then
@ -60,38 +62,44 @@ local codelens_hdlr = function(err, result, ctx, cfg)
for _, v in pairs(result) do
_update_sign(v.range.start.line)
end
end
local codelens_au
function M.setup(bufnr)
log('setup for ****** ', bufnr)
if codelens_au == nil then
vim.api.nvim_set_hl(0, 'LspCodeLens', { link = 'DiagnosticsHint', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensText', { link = 'DiagnosticsInformation', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensSign', { link = 'DiagnosticsInformation', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensSeparator', { link = 'Boolean', default = true })
codelens_au = vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('nv__codelenses', {}),
buffer = bufnr or vim.api.nvim_win_get_buf(),
callback = function()
require('navigator.codelens').refresh()
end,
})
end
end)
function M.setup()
vim.cmd('highlight! link LspCodeLens LspDiagnosticsHint')
vim.cmd('highlight! link LspCodeLensText LspDiagnosticsInformation')
vim.cmd('highlight! link LspCodeLensTextSign LspDiagnosticsSignInformation')
vim.cmd('highlight! link LspCodeLensTextSeparator Boolean')
vim.cmd('augroup navigator.codelenses')
vim.cmd(' autocmd!')
vim.cmd("autocmd BufEnter,CursorHold,InsertLeave <buffer> lua require('navigator.codelens').refresh()")
vim.cmd('augroup end')
local on_codelens = vim.lsp.handlers['textDocument/codeLens']
vim.lsp.handlers['textDocument/codeLens'] = mk_handler(function(err, result, ctx, cfg)
-- trace(err, result, ctx.client_id, ctx.bufnr, cfg or {})
cfg = cfg or {}
ctx = ctx or { bufnr = vim.api.nvim_get_current_buf() }
if nvim_0_6() then
on_codelens(err, result, ctx, cfg)
codelens_hdlr(err, result, ctx, cfg)
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
M.lsp_clients = {}
function M.refresh()
local bufnr = vim.api.nvim_get_current_buf()
if next(vim.lsp.get_clients({ buffer = bufnr })) == nil then
if #vim.lsp.buf_get_clients() < 1 then
log('Must have a client running to use lsp code action')
return
end
if not lsphelper.check_capabilities('codeLensProvider', bufnr) then
if not lsphelper.check_capabilities('code_lens') then
return
end
M.inline()
vim.lsp.codelens.refresh()
end
local virtual_types_ns = api.nvim_create_namespace('ng_virtual_types')
@ -102,16 +110,20 @@ function M.disable()
is_enabled = false
end
function M.run_action()
local original_select = vim.ui.select
vim.ui.select = require('guihua.gui').select
vim.ui.select = require("guihua.gui").select
log('codelens action')
log('codeaction')
codelens.run()
vim.defer_fn(function()
vim.ui.select = original_select
end, 1000)
vim.defer_fn(
function ()
vim.ui.select = original_select
end, 1000
)
end
M.inline = function()
@ -122,38 +134,47 @@ M.inline = function()
if vim.fn.getcmdwintype() == ':' then
return
end
local bufnr = api.nvim_get_current_buf()
if next(vim.lsp.get_clients({ buffer = bufnr })) == nil then
return
end
if vim.tbl_contains(M.disabled, bufnr) then
if #vim.lsp.buf_get_clients() == 0 then
return
end
local bufnr = api.nvim_get_current_buf()
local parameter = lsp.util.make_position_params()
local on_codelens = vim.lsp.handlers['textDocument/codeLens']
local ids = lsp.buf_request(bufnr, 'textDocument/codeLens', parameter, function(err, response, ctx, _)
if err then
log('lsp code lens', vim.inspect(err), ctx)
-- lets disable code lens for this buffer
vim.list_extend(M.disabled, { vim.api.nvim_get_current_buf() })
return
local response = lsp.buf_request_sync(bufnr, 'textDocument/codeLens', parameter)
-- Clear previous highlighting
api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
if response then
log(response)
for _, v in ipairs(response) do
if v == nil or v.result == nil then
return
end -- no response
for _, vv in pairs(v.result) do
local start_line = -1
for _, vvv in pairs(vv.range) do
start_line = tonumber(vvv.line)
end
local cmd = vv.command
local msg = _NgConfigValues.icons.code_action_icon .. ' '
if cmd then
local txt = cmd.title or ''
txt = txt .. ' ' .. (cmd.command or '') .. ' '
msg = msg .. txt .. ' '
end
log(msg)
api.nvim_buf_set_extmark(bufnr, virtual_types_ns, start_line, -1, {
virt_text = { { msg, 'LspCodeLensText' } },
virt_text_pos = 'overlay',
hl_mode = 'combine',
})
end
end
-- Clear previous highlighting
api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
if response then
trace(response)
on_codelens(err, response, ctx, _)
codelens_hdlr(err, response, ctx, _)
end
end)
if next(ids) == nil then
vim.list_extend(M.disabled, { vim.api.nvim_get_current_buf() })
-- else
-- api.nvim_command("echohl WarningMsg | echo 'VirtualTypes: No response' | echohl None")
end
end

@ -1,191 +0,0 @@
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-force=' .. lang
cmd = cmd .. ' ' .. options
cmd = string.format('%s -f %s %s --language-force=%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.log.levels.ERROR)
else
vim.notify('ctags generated')
end
end,
})
end
local symbols_to_items = require('navigator.lspwrapper').symbols_to_items
local function ctags_symbols()
local height = _NgConfigValues.height or 0.4
local width = _NgConfigValues.width or 0.7
height = math.floor(height * vfn.winheight('%'))
width = math.floor(vim.api.nvim_get_option('columns') * width)
local items = {}
local ctags_file = _NgConfigValues.ctags.tagfile
-- the tagfile name can be either .tags or tags
if vim.fn.filereadable(ctags_file) == 0 then
if vim.fn.filereadable('tags') == 1 then -- for some config the default tagfile is tags
ctags_file = 'tags'
_NgConfigValues.ctags.tagfile = 'tags'
end
end
if not util.file_exists(ctags_file) then
ctags_gen()
vim.cmd('sleep 400m')
end
local cnts = util.io_read(ctags_file)
if cnts == nil then
return vim.notify('ctags file ' .. ctags_file .. ' not found')
end
cnts = vfn.split(cnts, '\n')
for _, value in pairs(cnts) do
local it = entry_to_item(value)
if it then
table.insert(items, it)
end
end
cnts = nil
local ft = vim.o.ft
local result = symbols_to_items(items)
if next(result) == nil then
return vim.notify('no symbols found')
end
log(result[1])
local opt = {
api = '',
ft = ft,
bg = 'GuihuaListDark',
data = result,
items = result,
enter = true,
loc = 'top_center',
transparency = 50,
prompt = true,
rawdata = true,
title = 'ctags',
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,
}

@ -1,14 +1,9 @@
local M = {}
local uv = vim.uv or vim.loop
function M.debounce_trailing(ms, fn)
local timer = uv.new_timer()
local timer = vim.loop.new_timer()
return function(...)
local argv = {...}
if timer:is_active() then
timer:stop()
return
end
timer:start(ms, 0, function()
timer:stop()
fn(unpack(argv))
@ -17,7 +12,7 @@ function M.debounce_trailing(ms, fn)
end
function M.throttle_leading(ms, fn)
local timer = uv.new_timer()
local timer = vim.loop.new_timer()
local running = false
return function(...)
if not running then

@ -3,87 +3,65 @@ local lsphelper = require('navigator.lspwrapper')
local locations_to_items = lsphelper.locations_to_items
local gui = require('navigator.gui')
local log = util.log
local trace = util.trace
local TextView = require('guihua.textview')
-- callback for lsp definition, implementation and declaration handler
local definition_hdlr = function(err, locations, ctx, _)
local definition_hdlr = util.mk_handler(function(err, locations, ctx, _)
-- log(locations)
if err ~= nil then
if tostring(err):find('no type definition') or tostring(err):find('invalid range') then
vim.notify('Definition: ' .. tostring(err), vim.log.levels.DEBUG)
return vim.lsp.buf.hover() -- this is a primitive type
elseif tostring(err):find('no identifier') then
return vim.notify('Definition: ' .. tostring(err), vim.log.levels.DEBUG)
end
vim.notify('Defination: ' .. tostring(err) .. vim.inspect(ctx), vim.log.levels.WARN)
vim.notify('Defination: ', tostring(err) .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
return
end
if locations == nil or vim.tbl_isempty(locations) or type(locations) == 'number' then
if type(locations) == 'number' then
log(locations)
log('unable to handle request')
end
if locations == nil or vim.tbl_isempty(locations) then
vim.notify('Definition not found')
return
end
local oe = require('navigator.util').encoding(ctx.client_id)
locations = util.dedup(locations)
log(locations)
log('found ' .. #locations .. ' locations')
if vim.islist(locations) then
if vim.tbl_islist(locations) then
if #locations > 1 then
local items = locations_to_items(locations)
gui.new_list_view({ items = items, api = 'Definition', title = 'Definition' })
gui.new_list_view({ items = items, api = 'Definition' })
else
local loc = vim.lsp.util.make_position_params()
-- let check if the location is same as current
if
loc.textDocument.uri == locations[1].uri
and loc.position.line == locations[1].range.start.line
and loc.position.character == locations[1].range.start.character
then
vim.lsp.buf.type_definition()
else
vim.lsp.util.jump_to_location(locations[1], oe)
end
vim.lsp.util.jump_to_location(locations[1], oe)
end
else
return
vim.lsp.util.jump_to_location(locations, oe)
end
return true
end
end)
local function get_symbol()
local currentWord = vim.fn.expand('<cword>')
return currentWord
end
local function def_preview(timeout_ms, method)
assert(next(vim.lsp.get_clients({ buffer = 0 })), 'Must have a client running')
method = method or 'textDocument/definition'
local function def_preview(timeout_ms)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running')
local method = 'textDocument/definition'
local params = vim.lsp.util.make_position_params()
local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000)
if result == nil or vim.tbl_isempty(result) then
vim.notify('No result found: ' .. method, vim.log.levels.WARN)
return
vim.notify('No result found: ' .. method, vim.lsp.log_levels.WARN)
return nil
end
log(result)
if not vim.islist(result) then
return
end
local data = {}
-- result = {vim.tbl_deep_extend("force", {}, unpack(result))}
-- log("def-preview", result)
for _, value in pairs(result) do
if value ~= nil and value.result ~= nil and not vim.tbl_isempty(value.result) then
for key, value in pairs(result) do
if result[key] ~= nil and not vim.tbl_isempty(result[key]) then
table.insert(data, value.result[1])
end
end
if vim.tbl_isempty(data) then
vim.notify('No result found: ' .. method, vim.log.levels.WARN)
return
vim.notify('No result found: ' .. method, vim.lsp.log_levels.WARN)
return nil
end
local range = data[1].targetRange or data[1].range or data[1].targetSelectionRange
@ -91,7 +69,7 @@ local function def_preview(timeout_ms, method)
local row = range.start.line
-- in case there are comments
row = math.max(row - 3, 1)
local delta = range.start.line - row + 3
local delta = range.start.line - row + 1
local uri = data[1].uri or data[1].targetUri
if not uri then
return
@ -102,45 +80,32 @@ local function def_preview(timeout_ms, method)
end
local ok, parsers = pcall(require, 'nvim-treesitter.parsers')
if not ok then
return
end
-- TODO: 32/64 should be an option
local lines_num = 64
if range['end'] ~= nil then
lines_num = math.max(lines_num, range['end'].line - range.start.line + 4)
end
local lines_num = 12
if ok then
local ts = require('navigator.treesitter')
local root = parsers.get_parser(bufnr)
log(range)
if ts == nil then
return
end
local def_node = ts.get_node_at_pos({ range['start'].line, range['start'].character }, root)
local sr, _, er, _ = ts.get_node_scope(def_node)
log(sr, er)
lines_num = math.max(lines_num, er - sr + 5) -- comments etc
lines_num = math.max(lines_num, er - sr + 3) -- comments etc
end
-- TODO: 32 should be an option
-- TODO: 12 should be an option
local definition = vim.api.nvim_buf_get_lines(bufnr, row, range['end'].line + lines_num, false)
local def_line = vim.api.nvim_buf_get_lines(bufnr, range.start.line, range.start.line + 1, false)
for _ = 1, math.min(3, #definition), 1 do
if #definition[1] < 2 then
table.remove(definition, 1)
delta = delta - 1
row = row + 1
else
break
end
end
local width = 40
local maxwidth = math.floor(vim.api.nvim_get_option('columns') * 0.8)
for _, value in pairs(definition) do
local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5)
for key, value in pairs(definition) do
-- log(key, value, width)
width = math.max(width, #value + 4)
width = math.min(maxwidth, width)
@ -153,23 +118,13 @@ local function def_preview(timeout_ms, method)
relative = 'cursor',
style = 'minimal',
ft = filetype,
rect = { width = width, height = math.min(#definition + 3, 16), pos_y = 2 }, -- TODO: 16 hardcoded
rect = { width = width, height = #definition + 3 },
data = definition,
enter = true,
border = _NgConfigValues.border or 'shadow',
}
local view = TextView:new(opts)
log(view.buf)
vim.keymap.set('n', 'K', function()
local par = vim.lsp.util.make_position_params()
log(row, par, data[1])
par.position.line = par.position.line + row - 1 -- header 1
par.textDocument.uri = data[1].uri
log(par)
local bufnr_org = vim.uri_to_bufnr(data[1].uri)
return vim.lsp.buf_request(bufnr_org, 'textDocument/hover', par)
end, { buffer = view.buf })
TextView:new(opts)
delta = delta + 1 -- header
local cmd = 'normal! ' .. tostring(delta) .. 'G'
@ -180,31 +135,26 @@ local function def_preview(timeout_ms, method)
-- log(def_line[1], niddle)
vim.fn.matchadd('Search', niddle)
end
return true -- disable key-remap fallback
-- TODO:
-- https://github.com/oblitum/goyo.vim/blob/master/autoload/goyo.vim#L108-L135
end
local function type_preview(timeout_ms)
return def_preview(timeout_ms, 'textDocument/typeDefinition')
end
local def = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
util.for_each_buffer_client(bufnr, function(client, _, _bufnr)
-- if client.resolved_capabilities.goto_definition then
if client.server_capabilities.definitionProvider then
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
if client.resolved_capabilities.goto_definition then
client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr)
return
end
end)
end
vim.lsp.handlers['textDocument/definition'] = definition_hdlr
return {
definition = def,
definition_handler = definition_hdlr,
definition_preview = def_preview,
type_definition_preview = type_preview,
declaration_handler = definition_hdlr,
type_definition_handler = definition_hdlr,
typeDefinition_handler = definition_hdlr,
}

@ -1,28 +1,37 @@
local gui = require('navigator.gui')
local uv = vim.uv or vim.loop
local diagnostic_list = {}
local diagnostic = vim.diagnostic or vim.lsp.diagnostic
-- local hide = diagnostic.hide or diagnostic.clear
_NG_VT_DIAG_NS = vim.api.nvim_create_namespace('navigator_lua_diag')
local util = require('navigator.util')
local log = util.log
local trace = require('guihua.log').trace
-- trace = log
local error = util.error
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 empty = util.empty
local api = vim.api
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
util.nvim_0_8()
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
local diag_map = {
Error = vim.diagnostic.severity.ERROR,
Warning = vim.diagnostic.severity.WARN,
Info = vim.diagnostic.severity.Info,
Hint = vim.diagnostic.severity.Hint,
}
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
local diagnostic_cfg
local diag_map = {}
if vim.diagnostic then
diag_map = {
Error = vim.diagnostic.severity.ERROR,
Warning = vim.diagnostic.severity.WARN,
Info = vim.diagnostic.severity.Info,
Hint = vim.diagnostic.severity.Hint,
}
end
local function get_count(bufnr, level)
if vim.diagnostic ~= nil then
@ -32,10 +41,6 @@ local function get_count(bufnr, level)
end
end
local M = {}
M.diagnostic_list = {}
M.diagnostic_list[vim.bo.filetype] = {}
local function error_marker(result, ctx, config)
if
_NgConfigValues.lsp.diagnostic_scrollbar_sign == nil
@ -45,31 +50,26 @@ local function error_marker(result, ctx, config)
return
end
local async
async = uv.new_async(vim.schedule_wrap(function()
vim.defer_fn(function()
if vim.tbl_isempty(result.diagnostics) then
return
end
local first_line = vim.fn.line('w0')
local last_line = vim.fn.line('w$')
local weight = last_line - first_line + 1 -- local rootfolder = vim.fn.expand('%:h:t') -- get the current file root folder
-- local rootfolder = vim.fn.expand('%:h:t') -- get the current file root folder
local bufnr = ctx.bufnr
if bufnr == nil and result.uri then
bufnr = vim.uri_to_bufnr(result.uri) or vim.api.nvim_get_current_buf()
end
local success, fname = pcall(api.nvim_buf_get_name, bufnr)
if not success then
return
if bufnr == nil then
bufnr = vim.uri_to_bufnr(result.uri)
end
local fname = vim.api.nvim_buf_get_name(bufnr)
local uri = vim.uri_from_fname(fname)
if uri ~= result.uri then
log('not same buf', ctx, result.uri, bufnr, vim.fn.bufnr())
return
end
if not api.nvim_buf_is_loaded(bufnr) then
trace('buf not loaded', bufnr)
if not vim.api.nvim_buf_is_loaded(bufnr) then
log('buf not loaded', bufnr)
return
end
@ -80,21 +80,28 @@ local function error_marker(result, ctx, config)
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
log('great no errors')
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
return
end
local total_num = api.nvim_buf_line_count(bufnr)
if total_num == 0 then
return
end
-- total line num of current buffer
-- local winid = vim.fn.win_getid(vim.fn.winnr())
-- local winid = vim.api.nvim_get_current_win()
local total_num = vim.api.nvim_buf_line_count(bufnr)
-- local total_num = vim.fn.getbufinfo(vim.fn.winbufnr(winid))[1].linecount
-- window size of current buffer
if total_num < weight then
weight = total_num
local stats = vim.api.nvim_list_uis()[1]
-- local wwidth = stats.width;
local wheight = stats.height
if total_num <= wheight then
return
end
if _NG_VT_DIAG_NS == nil then
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
_NG_VT_DIAG_NS = vim.api.nvim_create_namespace('navigator_lua_diag')
end
local pos = {}
@ -105,7 +112,7 @@ local function error_marker(result, ctx, config)
diags[i].range = { start = { line = diags[i].lnum } }
end
end
local ratio = weight / total_num
table.sort(diags, function(a, b)
return a.range.start.line < b.range.start.line
end)
@ -116,16 +123,14 @@ local function error_marker(result, ctx, config)
diag.range = { start = { line = diag.lnum } }
end
if diag.range and diag.range.start and diag.range.start.line then
p = diag.range.start.line + 1 -- convert to 1 based
p = util.round(p * ratio, ratio)
trace('pos: ', diag.range.start.line, p)
p = diag.range.start.line
p = util.round(p * wheight / math.max(wheight, total_num))
if pos[#pos] and pos[#pos].line == p then
local bar = _NgConfigValues.lsp.diagnostic_scrollbar_sign[2]
if pos[#pos] == bar then
bar = _NgConfigValues.lsp.diagnostic_scrollbar_sign[3]
end
pos[#pos] =
{ line = p, sign = bar, severity = math.min(diag.severity, pos[#pos].severity) }
pos[#pos] = { line = p, sign = bar, severity = math.min(diag.severity, pos[#pos].severity) }
else
table.insert(pos, {
line = p,
@ -137,8 +142,10 @@ local function error_marker(result, ctx, config)
trace('pos, line:', p, diag.severity, diag.range)
end
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
for _, s in pairs(pos) do
if not vim.tbl_isempty(pos) then
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
end
for i, s in pairs(pos) do
local hl = 'ErrorMsg'
if type(s.severity) == 'number' then
if s.severity == 2 then
@ -151,17 +158,13 @@ local function error_marker(result, ctx, config)
hl = 'WarningMsg'
end
end
local l = s.line + first_line - 1 -- convert back to 0 based
if l > total_num - 1 then
l = total_num - 1
end
if l < 0 then
l = 0
local l = s.line + first_line
if l > total_num then
l = total_num
end
trace('add pos', s, bufnr)
trace('add pos', s, bufnr, l)
api.nvim_buf_set_extmark(
vim.api.nvim_buf_set_extmark(
bufnr,
_NG_VT_DIAG_NS,
l,
@ -169,49 +172,53 @@ local function error_marker(result, ctx, config)
{ virt_text = { { s.sign, hl } }, virt_text_pos = 'right_align' }
)
end
async:close()
end))
vim.defer_fn(function()
async:send()
end, 10)
end, 10) -- defer in 10ms
end
local update_err_marker_async = function()
local debounce = require('navigator.debounce').debounce_trailing
return debounce(500, error_marker)
return debounce(400, error_marker)
end
local diag_hdlr = function(err, result, ctx, config)
require('navigator.lspclient.highlight').config_signs()
config = config or diagnostic_cfg
local diag_hdlr = mk_handler(function(err, result, ctx, config)
require('navigator.lspclient.highlight').diagnositc_config_sign()
if err ~= nil then
log(err, config, result)
return
end
local mode = api.nvim_get_mode().mode
local mode = vim.api.nvim_get_mode().mode
if mode ~= 'n' and config.update_in_insert == false then
trace('skip sign update in insert mode')
log('skip sign update in insert mode')
end
local cwd = uv.cwd()
local cwd = vim.loop.cwd()
local ft = vim.bo.filetype
if M.diagnostic_list[ft] == nil then
M.diagnostic_list[vim.bo.filetype] = {}
if diagnostic_list[ft] == nil then
diagnostic_list[vim.bo.filetype] = {}
end
local client_id = ctx.client_id
local bufnr = ctx.bufnr or 0
if result.diagnostics ~= nil and result.diagnostics ~= {} then
trace('diagnostic', result.diagnostics, ctx, config)
end
trace('diag', err, mode, result, ctx, config)
vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
if util.nvim_0_6() then
trace(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 diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if empty(result.diagnostics) and diag_cnt > 0 then
trace('no result? ', diag_cnt)
log('no result? ', diag_cnt)
return
end
-- trace("diag: ", mode, result, ctx, config)
if result and result.diagnostics then
local item_list = {}
for _, v in ipairs(result.diagnostics) do
@ -223,21 +230,14 @@ local diag_hdlr = function(err, result, ctx, config)
item.uri = uri
-- trace(item)
local head = _NgConfigValues.icons.diagnostic_head
if v.severity then
if v.severity == 1 then
head = _NgConfigValues.icons.diagnostic_head_severity_1
end
if v.severity == 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_2
end
if v.severity > 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_3
end
else
v.severity = 3
if v.severity == 1 then
head = _NgConfigValues.icons.diagnostic_head_severity_1
end
if v.severity == 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_2
end
if not _NgConfigValues.icons.icons then
head = ''
if v.severity > 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_3
end
if v.relatedInformation and v.relatedInformation[1] then
local info = v.relatedInformation[1]
@ -250,12 +250,7 @@ local diag_hdlr = function(err, result, ctx, config)
end
end
local bufnr1 = vim.uri_to_bufnr(uri)
local loaded = api.nvim_buf_is_loaded(bufnr1)
local ic = _NgConfigValues.icons.diagnostic_head_description
if not _NgConfigValues.icons.icons then
ic = ''
end
local loaded = vim.api.nvim_buf_is_loaded(bufnr1)
if _NgConfigValues.diagnostic_load_files then
-- print('load buffers')
if not loaded then
@ -263,14 +258,14 @@ local diag_hdlr = function(err, result, ctx, config)
end
local pos = v.range.start
local row = pos.line
local line = (api.nvim_buf_get_lines(bufnr1, row, row + 1, false) or { '' })[1]
local line = (vim.api.nvim_buf_get_lines(bufnr1, row, row + 1, false) or { '' })[1]
if line ~= nil then
item.text = head .. line .. ic .. v.message
item.text = head .. line .. _NgConfigValues.icons.diagnostic_head_description .. v.message
else
error('diagnostic result empty line' .. tostring(row))
error('diagnostic result empty line', v, row, bufnr1)
end
else
item.text = head .. ic .. v.message
item.text = head .. _NgConfigValues.icons.diagnostic_head_description .. v.message
end
if v.releated_msg then
@ -284,11 +279,11 @@ local diag_hdlr = function(err, result, ctx, config)
table.insert(item_list, item)
end
-- local old_items = vim.fn.getqflist()
if M.diagnostic_list[ft][uri] == nil then
M.diagnostic_list[ft][uri] = {}
if diagnostic_list[ft][uri] == nil then
diagnostic_list[ft][uri] = {}
end
M.diagnostic_list[ft][uri][tostring(client_id)] = item_list
-- trace(uri, ft, M.diagnostic_list)
diagnostic_list[ft][uri][tostring(client_id)] = item_list
trace(uri, ft, diagnostic_list)
if not result.uri then
result.uri = uri
end
@ -297,149 +292,57 @@ local diag_hdlr = function(err, result, ctx, config)
marker(result, ctx, config)
else
trace('great, no diag errors')
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
end
end
local function diag_signs()
if not _NgConfigValues.lsp.diagnostic or _NgConfigValues.lsp.diagnostic.signs == false then
return
end
local icons = _NgConfigValues.icons
if icons.icons then
local e, w, i, h =
icons.diagnostic_err, icons.diagnostic_warn, icons.diagnostic_info, icons.diagnostic_hint
local t = vim.fn.sign_getdefined('DiagnosticSignWarn')
local text = {
[vim.diagnostic.severity.ERROR] = e,
[vim.diagnostic.severity.WARN] = w,
[vim.diagnostic.severity.INFO] = i,
[vim.diagnostic.severity.HINT] = h,
}
-- in case there are duplicated signs defined in _NgConfigValues.lsp.diagnostic.signs
if
_NgConfigValues.lsp.diagnostic.signs
and type(_NgConfigValues.lsp.diagnostic.signs) == 'table'
and _NgConfigValues.lsp.diagnostic.signs.text
then
for k, v in pairs(_NgConfigValues.lsp.diagnostic.signs) do
text[k] = v
end
end
-- text must have at least one sign
local signs_valid = false
for _, v in pairs(text) do
if v then
signs_valid = true
break
end
end
if
vim.tbl_isempty(t) or (t[1] and t[1].text and t[1].text:find('W')) and signs_valid == true
then
log('set signs ', text)
return {
text = text,
}
end
end
end
-- goto next Error if none found, go to first
function M.goto_next(opts)
opts = opts or {}
local bufnr = api.nvim_get_current_buf()
local diags = diagnostic.get(bufnr, { severity = vim.diagnostic.severity.ERROR })
if diags and #diags > 0 then
opts.severity = vim.diagnostic.severity.ERROR
return diagnostic.goto_next(opts)
end
diagnostic.goto_next(opts)
end
end)
function M.goto_prev(opts)
opts = opts or {}
local bufnr = api.nvim_get_current_buf()
local diags = diagnostic.get(bufnr, { severity = vim.diagnostic.severity.ERROR })
if diags and #diags > 0 then
opts.severity = vim.diagnostic.severity.ERROR
return diagnostic.goto_prev(opts)
end
diagnostic.goto_prev(opts)
local diag_hdlr_async = function()
local debounce = require('navigator.debounce').debounce_trailing
return debounce(100, diag_hdlr)
end
-- local diag_hdlr_async = function()
-- local debounce = require('navigator.debounce').debounce_trailing
-- return debounce(100, diag_hdlr)
-- end
function M.setup(cfg)
if diagnostic_cfg ~= nil and diagnostic_cfg.float ~= nil then
return
end
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.diagnostic_virtual_text },
-- 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 },
}
local signs = diag_signs()
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
update_in_insert = _NgConfigValues.lsp.diagnostic.update_in_insert or false,
severity_sort = _NgConfigValues.lsp.diagnostic.severity_sort,
float = _NgConfigValues.lsp.diagnostic.float,
}
if type(signs) == 'table' then
diagnostic_cfg.signs = signs
end
diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text
if
type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' and _NgConfigValues.icons.icons
then
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text
end
-- vim.lsp.handlers["textDocument/publishDiagnostics"]
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
diagnostic_cfg = vim.tbl_extend('force', diagnostic_cfg, cfg)
vim.diagnostic.config(diagnostic_cfg)
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
api.nvim_create_autocmd({ 'WinScrolled' }, {
group = api.nvim_create_augroup('NGWinScrolledGroup', { clear = false }),
pattern = '*',
callback = function()
require('navigator.diagnostics').update_err_marker()
end,
})
end
if _NgConfigValues.lsp.diagnostic_virtual_text == false then
diagnostic_cfg.virtual_text = false
end
local function clear_diag_VT(bufnr) -- important for clearing out when no more errors
bufnr = bufnr or api.nvim_get_current_buf()
log(bufnr, _NG_VT_DIAG_NS)
if _NG_VT_DIAG_NS == nil then
return
end
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
-- vim.lsp.handlers["textDocument/publishDiagnostics"]
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
M.hide_diagnostic = function()
if _NG_VT_DIAG_NS then
clear_diag_VT()
vim.api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
end
M.toggle_diagnostics = function()
M.diagnostic_enabled = not vim.diagnostic.enable()
vim.diagnostic.enable(M.diagnostic_enabled)
if M.diagnostic_enabled then
M.diagnostic_enabled = false
return vim.diagnostic.disable()
end
vim.diagnostic.enable()
M.diagnostic_enabled = true
end
M.show_buf_diagnostics = function()
if M.diagnostic_list[vim.bo.filetype] ~= nil then
local results = M.diagnostic_list[vim.bo.filetype]
if diagnostic_list[vim.bo.filetype] ~= nil then
-- log(diagnostic_list[vim.bo.filetype])
-- vim.fn.setqflist({}, " ", {title = "LSP", items = diagnostic_list[vim.bo.filetype]})
local results = diagnostic_list[vim.bo.filetype]
local display_items = {}
for _, client_items in pairs(results) do
for _, items in pairs(client_items) do
@ -452,54 +355,38 @@ M.show_buf_diagnostics = function()
if #display_items > 0 then
local listview = gui.new_list_view({
items = display_items,
api = _NgConfigValues.icons.diagnostic_file
.. _NgConfigValues.icons.diagnostic_head
.. ' Diagnostic ',
api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. ' Diagnostic ',
enable_preview_edit = true,
title = 'LSP Diagnostic',
})
if listview == nil then
return log('nil listview')
end
trace('new buffer', listview.bufnr)
if listview.bufnr then
api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
end
vim.api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
end
end
end
-- set loc list win
M.setloclist = function(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
M.set_diag_loclist = function()
local bufnr = vim.api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 then
log('great, no errors!')
-- vim.fn.getloclist(0, {filewinid=0})
return vim.cmd('lclose')
return
end
local clients = vim.lsp.get_clients({ buffer = bufnr })
local clients = vim.lsp.buf_get_clients(0)
local cfg = { open = diag_cnt > 0 }
for _, client in pairs(clients) do
cfg.client_id = client['id']
break
end
if not vim.tbl_isempty(vim.lsp.get_clients({ buffer = bufnr })) then
if not vim.tbl_isempty(vim.lsp.buf_get_clients(0)) then
local err_cnt = get_count(0, [[Error]])
if err_cnt > 0 then
if _NgConfigValues.lsp.display_diagnostic_qf then
if _NgConfigValues.lsp.display_diagnostic_qf == 'trouble' then
vim.cmd('Trouble')
else
cfg.namespaces = diagnostic.get_namespaces()
cfg.open = true
diagnostic.setloclist(cfg)
end
if err_cnt > 0 and _NgConfigValues.lsp.disply_diagnostic_qf then
if diagnostic.set_loclist then
diagnostic.set_loclist(cfg)
else
vim.notify('Error count: ' .. tostring(err_cnt) .. ' please check quickfix')
cfg.namespaces = diagnostic.get_namespace(nil)
diagnostic.setloclist(cfg)
end
else
vim.cmd('lclose')
@ -514,7 +401,7 @@ function M.update_err_marker()
-- nothing to update
return
end
local bufnr = api.nvim_get_current_buf()
local bufnr = vim.api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]])
+ get_count(bufnr, [[Warning]])
@ -523,11 +410,12 @@ function M.update_err_marker()
-- redraw
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
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)
trace('no errors')
return
end
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
local errors = diagnostic.get(bufnr)
if #errors == 0 then
trace('no errors', errors)
@ -541,67 +429,35 @@ function M.update_err_marker()
marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' })
end
function M.get_line_diagnostic()
local lnum = api.nvim_win_get_cursor(0)[1] - 1
local diags = diagnostic.get(api.nvim_get_current_buf(), { lnum = lnum })
-- 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
local l = 0
local cmp = function(d1, d2)
return d1.severity < d2.severity
end
table.sort(diags, cmp)
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
vim.cmd([[autocmd WinScrolled * lua require'navigator.diagnostics'.update_err_marker()]])
end
return diags
function M.get_line_diagnostic()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
return diagnostic.get(vim.api.nvim_get_current_buf(), { lnum = lnum })
end
function M.show_diagnostics(pos)
local bufnr = api.nvim_get_current_buf()
local lnum, col = unpack(api.nvim_win_get_cursor(0))
lnum = lnum - 1
local opt = { border = 'single', severity_sort = true }
if pos ~= nil and type(pos) == 'number' then
opt.scope = 'buffer'
else
local bufnr = vim.api.nvim_get_current_buf()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
local opt = { border = 'single' }
if diagnostic.open_float and type(diagnostic.open_float) == 'function' then
if pos == true then
opt.scope = 'cursor'
else
opt.scope = 'line'
end
diagnostic.open_float(bufnr, opt)
else
-- deprecated
diagnostic.show_line_diagnostics(opt, bufnr, lnum)
end
local diags = M.get_line_diagnostic()
if diags == nil or next(diags) == nil then
return
end
-- if there is diagnostic at cursor position, show only that diagnostic
local line_length = #api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1]
local diags_cursor = vim.tbl_filter(function(d)
return d.lnum == lnum
and math.min(d.col, line_length - 1) <= col
and (d.end_col >= col or d.end_lnum > lnum)
end, diags)
if #diags_cursor > 0 then
opt.scope = 'cursor'
diags = diags_cursor
end
local diag1 = diags[1]
opt.offset_x = -1 * (col - diag1.col)
diagnostic.open_float(bufnr, opt)
end
function M.config(cfg)
cfg = cfg or {}
log('diag config', cfg)
local default_cfg = {}
cfg = vim.tbl_extend('keep', cfg, default_cfg)
if vim.diagnostic == nil then
vim.notify('deprecated: please update nvim to 0.7+')
return
end
M.setup(cfg)
end
return M

@ -1,6 +1,7 @@
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local mk_handler = util.mk_handler
local api = vim.api
local references = {}
_NG_hi_list = {}
@ -17,10 +18,7 @@ local function add_locs(bufnr, result)
if #result < 1 then
return
end
local winid = vim.fn.bufwinid(0)
symbol =
string.format('%s_%i_%i_%i_%i', symbol, bufnr, result[1].range.start.line, result[1].range.start.character, winid)
symbol = string.format('%s_%i_%i_%i', symbol, bufnr, result[1].range.start.line, result[1].range.start.character)
if _NG_hi_list[symbol] == nil then
_NG_hi_list[symbol] = { range = {} }
end
@ -35,33 +33,23 @@ local function add_locs(bufnr, result)
end
local function nohl()
local winid = vim.fn.bufwinid(0)
for key, value in pairs(_NG_hi_list) do
if value.hi_ids ~= nil then
local del = false
for _, v in ipairs(value.hi_ids) do
trace('delete', v)
if v[2] == winid then
del = true
vim.fn.matchdelete(v[1])
end
end
if del then
_NG_hi_list[key].hi_ids = nil
vim.fn.matchdelete(v)
end
_NG_hi_list[key].hi_ids = nil
end
end
end
-- toggle highlight for current symbol
local function hi_symbol()
local symbol_wd = get_symbol()
local symbol = _NG_current_symbol
if string.find(symbol, symbol_wd) ~= 1 then
if string.find(symbol, symbol_wd) == nil then
vim.lsp.buf.document_highlight()
return vim.defer_fn(function()
hi_symbol()
end, 500)
symbol = _NG_current_symbol
end
if symbol == nil or symbol == '' then
log('nil symbol')
@ -73,12 +61,11 @@ local function hi_symbol()
_NG_ref_hi_idx = 1
end
-- if already highlighted; remove
local range = _NG_hi_list[symbol].range or {}
if _NG_hi_list[symbol].hi_ids ~= nil then
for _, value in ipairs(_NG_hi_list[symbol].hi_ids) do
log('delete', symbol, value)
vim.fn.matchdelete(value[1])
log('delete', value)
vim.fn.matchdelete(value)
end
_NG_hi_list[symbol].hi_ids = nil
return
@ -96,7 +83,6 @@ local function hi_symbol()
p = match_result:sub(1, p)
total_match = tonumber(p)
end
local winid = vim.fn.bufwinid(0)
if total_match == totalref then -- same number as matchpos
trace(total_match, 'use matchadd()')
local k = range[1].kind
@ -104,10 +90,10 @@ local function hi_symbol()
local m = string.format('\\<%s\\>', symbol_wd)
local r = vim.fn.matchadd(hi_name, m, 20)
trace('hi id', m, hi_name, r)
table.insert(_NG_hi_list[symbol].hi_ids, { r, winid })
table.insert(_NG_hi_list[symbol].hi_ids, r)
--
-- vim.fn.matchdelete(r)
else
trace(total_match, 'use matchadd()', totalref)
for _, value in ipairs(range) do
local k = value.kind
local l = value.range.start.line + 1
@ -122,7 +108,7 @@ local function hi_symbol()
local hi_name = string.format('NGHiReference_%i_%i', _NG_ref_hi_idx, k)
trace(hi_name, { l, cs, w })
local m = vim.fn.matchaddpos(hi_name, { { l, cs, w } }, 10)
table.insert(_NG_hi_list[symbol].hi_ids, { m, winid })
table.insert(_NG_hi_list[symbol].hi_ids, m)
end
end
@ -138,9 +124,6 @@ end
-- returns r1 < r2 based on start of range
local function before(r1, r2)
if not r1 or not r2 then
return false
end
if r1.start.line < r2.start.line then
return true
end
@ -153,13 +136,14 @@ local function before(r1, r2)
return false
end
local handle_document_highlight = function(_, result, ctx)
local handle_document_highlight = mk_handler(function(_, result, ctx)
trace(result, ctx)
if not ctx.bufnr then
log('ducment highlight error', result, ctx)
return
end
if type(result) ~= 'table' or vim.fn.empty(result) == 1 then
if type(result) ~= 'table' then
log('clear up', result)
vim.lsp.util.buf_clear_references(ctx.bufnr)
return
end
@ -170,7 +154,7 @@ local handle_document_highlight = function(_, result, ctx)
references[ctx.bufnr] = result
local client_id = ctx.client_id
vim.lsp.util.buf_highlight_references(ctx.bufnr, result, util.encoding(client_id))
end
end)
-- modify from vim-illuminate
local function goto_adjent_reference(opt)
trace(opt)
@ -219,67 +203,56 @@ local function cmd_nohl()
end
end
local nav_doc_hl = function(bufnr)
trace('nav_doc_hl', bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
_G.nav_doc_hl = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
util.for_each_buffer_client(bufnr, function(client, _, _)
if client.server_capabilities.documentHighlightProvider == true then
trace('sending doc highlight', client.name, bufnr)
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, bufnr)
if client.resolved_capabilities.document_highlight then
client.request('textDocument/documentHighlight', ref_params, handle_document_highlight, bufnr)
end
end)
end
local function documentHighlight(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
local function documentHighlight()
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
if _NgConfigValues.lsp.document_highlight == true then
local group_name = string.format('%s%d', 'NGHiGroup', bufnr)
local cmd_group = api.nvim_create_augroup(group_name, {})
api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
group = cmd_group,
buffer = bufnr,
desc = 'document highlight',
callback = function()
require('navigator.dochighlight').nav_doc_hl(bufnr)
end,
})
api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, {
group = cmd_group,
buffer = bufnr,
desc = 'clear document highlight',
callback = function()
vim.lsp.util.buf_clear_references(bufnr)
end,
})
end
vim.lsp.handlers['textDocument/documentHighlight'] = function(err, result, ctx)
local buffer = ctx.bufnr or api.nvim_get_current_buf()
augroup lsp_document_highlight
autocmd! * <buffer>
autocmd CursorHold <buffer> lua nav_doc_hl()
autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
augroup END
]],
false
)
vim.lsp.handlers['textDocument/documentHighlight'] = mk_handler(function(err, result, ctx)
local bufnr = ctx.bufnr or api.nvim_get_current_buf()
if err then
-- vim.notify('failed to highlight symbol' .. vim.inspect(err), vim.log.levels.ERROR, vim.log.levels.ERROR)
log('failed to highlight symbol', err)
vim.notify(err, vim.lsp.log_levels.ERROR)
return
end
if not result or not result[1] or not result[1]['range'] then
return
end
trace('dochl', result)
bufnr = bufnr or 0
if type(result) ~= 'table' then
vim.lsp.util.buf_clear_references(buffer)
vim.lsp.util.buf_clear_references(bufnr)
return
end
local client_id = ctx.client_id
vim.lsp.util.buf_clear_references(buffer)
vim.lsp.util.buf_highlight_references(buffer, result, util.encoding(client_id))
vim.lsp.util.buf_clear_references(bufnr)
vim.lsp.util.buf_highlight_references(bufnr, result, util.encoding(client_id))
table.sort(result, function(a, b)
return before(a.range, b.range)
end)
references[buffer] = result
add_locs(buffer, result)
end
references[bufnr] = result
add_locs(bufnr, result)
end)
end
return {
@ -288,6 +261,5 @@ return {
handle_document_highlight = handle_document_highlight,
hi_symbol = hi_symbol,
nohl = nohl,
nav_doc_hl = nav_doc_hl,
cmd_nohl = cmd_nohl,
}

@ -1,4 +1,5 @@
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 api = vim.api
@ -13,11 +14,11 @@ M.current_buf_folds = {}
M.servers_supporting_folding = {
pylsp = true,
pyright = false,
lua_ls = true,
sumneko_lua = true,
texlab = true,
clangd = false,
gopls = true,
julials = false,
julials = false
}
M.active_folding_clients = {}
@ -28,16 +29,21 @@ function M.on_attach()
end
function M.setup_plugin()
local cmd_group = api.nvim_create_augroup('NGFoldGroup', {})
api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost' }, {
group = cmd_group,
pattern = '*',
callback = function()
require('navigator.foldlsp').update_folds()
end,
})
local clients = vim.lsp.get_clients({buffer = 0})
api.nvim_command("augroup FoldingCommand")
api.nvim_command("autocmd! * <buffer>")
api.nvim_command("autocmd BufEnter <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command("autocmd BufWritePost <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command("augroup end")
-- vim.cmd([[
--
-- function! folding_nvim#foldexpr()
-- return luaeval(printf('require"navigator.foldlsp".get_fold_indic(%d)', v:lnum))
-- endfunction
--
-- ]])
local clients = vim.lsp.buf_get_clients()
for _, client in pairs(clients) do
local client_id = client['id']
@ -51,6 +57,7 @@ function M.setup_plugin()
M.active_folding_clients[client_id] = server_supports_folding
end
end
-- print(vim.inspect(M.active_folding_clients))
end
function M.update_folds()
@ -60,14 +67,15 @@ function M.update_folds()
-- In diff mode, use diff folding.
api.nvim_win_set_option(current_window, 'foldmethod', 'diff')
else
local clients = lsp.get_clients({buffer = 0})
local clients = lsp.buf_get_clients(0)
for client_id, client in pairs(clients) do
if M.active_folding_clients[client_id] then
-- XXX: better to pass callback in this method or add it directly in the config?
-- client.config.callbacks['textDocument/foldingRange'] = M.fold_handler
local current_bufnr = api.nvim_get_current_buf()
local params = { uri = vim.uri_from_bufnr(current_bufnr) }
client.request('textDocument/foldingRange', { textDocument = params }, M.fold_handler, current_bufnr)
local params = {uri = vim.uri_from_bufnr(current_bufnr)}
client.request('textDocument/foldingRange', {textDocument = params}, M.fold_handler,
current_bufnr)
end
end
end
@ -81,11 +89,11 @@ function M.debug_folds()
end
end
M.fold_handler = function(err, result, ctx, _)
M.fold_handler = mk_handler(function(err, result, ctx, config)
-- params: err, method, result, client_id, bufnr
-- XXX: handle err?
if err or result == nil or #result == 0 then
vim.notify(string.format('%s %s ', tostring(err), vim.inspect(ctx)), vim.log.levels.WARN)
vim.notify(string.format("%s %s ", tostring(err), vim.inspect(ctx)), vim.lsp.log_levels.WARN)
return
end
M.debug_folds()
@ -105,7 +113,7 @@ M.fold_handler = function(err, result, ctx, _)
api.nvim_win_set_option(current_window, 'foldmethod', 'expr')
api.nvim_win_set_option(current_window, 'foldexpr', 'foldlsp#foldexpr()')
end
end
end)
function M.adjust_foldstart(line_no)
return line_no + 1
@ -152,12 +160,13 @@ function M.get_fold_indic(lnum)
-- without any marker.
return fold_level
elseif is_foldstart then
return string.format('>%d', fold_level)
return string.format(">%d", fold_level)
elseif is_foldend then
return string.format('<%d', fold_level)
return string.format("<%d", fold_level)
else
return fold_level
end
end
return M

@ -1,7 +1,6 @@
-- NOTE: this file is a modified version of fold.lua from nvim-treesitter
local log = require('navigator.util').log
local trace = require('navigator.util').trace
local api = vim.api
local tsutils = require('nvim-treesitter.ts_utils')
local query = require('nvim-treesitter.query')
@ -9,211 +8,48 @@ local parsers = require('nvim-treesitter.parsers')
local get_node_at_line = require('navigator.treesitter').get_node_at_line
local M = {}
-- TODO: per-buffer fold table?
M.current_buf_folds = {}
function M.on_attach()
M.setup_fold()
-- M.update_folds()
end
local prefix = _NgConfigValues.icons.fold.prefix
local sep = _NgConfigValues.icons.fold.separator
-- vim.treesitter.foldtext was removed
-- • Removed `vim.treesitter.foldtext` as transparent foldtext is now supported
-- https://github.com/neovim/neovim/pull/20750
-- get the foldtext from treesitter
-- https://github.com/Wansmer/nvim-config/blob/main/lua/modules/foldtext.lua
local function parse_line(linenr)
local bufnr = vim.api.nvim_get_current_buf()
local line = vim.api.nvim_buf_get_lines(bufnr, linenr - 1, linenr, false)[1]
if not line then
return nil
end
local ok, parser = pcall(vim.treesitter.get_parser, bufnr)
if not ok then
return nil
end
local lang_query = vim.treesitter.query.get(parser:lang(), 'highlights')
if not lang_query then
return nil
end
local tree = parser:parse({ linenr - 1, linenr })[1]
local result = {}
local line_pos = 0
for id, node, metadata in lang_query:iter_captures(tree:root(), 0, linenr - 1, linenr) do
local name = lang_query.captures[id]
local start_row, start_col, end_row, end_col = node:range()
local priority = tonumber(metadata.priority or vim.highlight.priorities.treesitter)
if start_row == linenr - 1 and end_row == linenr - 1 then
-- check for characters ignored by treesitter
if start_col > line_pos then
table.insert(result, {
line:sub(line_pos + 1, start_col),
{ { 'Folded', priority } },
range = { line_pos, start_col },
})
end
line_pos = end_col
local text = line:sub(start_col + 1, end_col)
table.insert(result, { text, { { '@' .. name, priority } }, range = { start_col, end_col } })
end
end
local i = 1
while i <= #result do
-- find first capture that is not in current range and apply highlights on the way
local j = i + 1
while
j <= #result
and result[j].range[1] >= result[i].range[1]
and result[j].range[2] <= result[i].range[2]
do
for k, v in ipairs(result[i][2]) do
if not vim.tbl_contains(result[j][2], v) then
table.insert(result[j][2], k, v)
end
end
j = j + 1
end
-- remove the parent capture if it is split into children
if j > i + 1 then
table.remove(result, i)
else
-- highlights need to be sorted by priority, on equal prio, the deeper nested capture (earlier
-- in list) should be considered higher prio
if #result[i][2] > 1 then
table.sort(result[i][2], function(a, b)
return a[2] < b[2]
end)
end
result[i][2] = vim.tbl_map(function(tbl)
return tbl[1]
end, result[i][2])
result[i] = { result[i][1], result[i][2] }
i = i + 1
end
end
return result
end
function NG_custom_fold_text()
-- if vim.treesitter.foldtext then
local line_syntax = parse_line(vim.v.foldstart)
if type(line_syntax) ~= 'table' or #line_syntax < 1 then
return vim.fn.foldtext()
end
function _G.custom_fold_text()
local line = vim.fn.getline(vim.v.foldstart)
local line_count = vim.v.foldend - vim.v.foldstart + 1
if prefix ~= '' then
local spaces = line_syntax[1]
local s = spaces[1]
local first_char = s:sub(1, 1)
if first_char == '\t' then
local tabspace = string.rep(' ', vim.o.tabstop)
s = s:gsub('\t', tabspace)
end
s = s:gsub('^ ', prefix) -- replace prefix with two spaces
if s ~= spaces[1] then
spaces[1] = s
spaces[2] = { '@keyword' }
end
end
local sep2 = ' ' .. string.rep(sep, 1) .. ' '
table.insert(line_syntax, { '', { '@tag' } })
table.insert(line_syntax, { sep2, { '@tag' } })
table.insert(line_syntax, { tostring(line_count), { '@number' } })
table.insert(line_syntax, { ' lines', { '@text.title' } })
table.insert(line_syntax, { sep2, { '@tag' } })
return line_syntax
-- log("" .. line .. " // " .. line_count .. " lines")
return '' .. line .. ': ' .. line_count .. ' lines'
end
vim.opt.foldtext = NG_custom_fold_text()
vim.opt.foldtext = custom_fold_text()
vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options')
function M.setup_fold()
vim.opt.foldtext = 'v:lua.NG_custom_fold_text()'
-- vim.opt.viewoptions:remove('options')
local cmd_group = api.nvim_create_augroup('NGFoldGroup', {})
vim.api.nvim_create_autocmd({ 'BufWinEnter', 'WinEnter' }, {
group = cmd_group,
callback = function()
-- user should setup fillchars themself
-- vim.opt.fillchars = { foldclose = "", foldopen = "", vert = "│", fold = " ", diff = "░", msgsep = "‾", foldsep = "│" }
local current_window = api.nvim_get_current_win()
local in_diff_mode = api.nvim_win_get_option(current_window, 'diff')
if in_diff_mode then
-- In diff mode, use diff folding.
return
end
local current_window = api.nvim_get_current_win()
if not parsers.has_parser() then
api.nvim_win_set_option(current_window, 'foldmethod', 'indent')
log('fallback to indent folding')
return
end
log('setup treesitter folding winid', current_window)
api.nvim_set_option_value('foldexpr', 'folding#ngfoldexpr()', { win = current_window })
api.nvim_set_option_value('foldmethod', 'expr', { win = current_window })
end,
})
end
local function is_comment(line_number)
local node = get_node_at_line(line_number)
trace(line_number, node, node:type())
if not node then
return false
end
local node_type = node:type()
trace(line_number, node_type)
return node_type:find('comment')
if not parsers.has_parser() then
vim.notify('treesitter folding not enabled for current file', vim.lsp.log_levels.WARN)
return
end
log('setup treesitter folding')
api.nvim_command('augroup FoldingCommand')
api.nvim_command('autocmd! * <buffer>')
api.nvim_command('augroup end')
vim.opt.foldtext = 'v:lua.custom_fold_text()'
vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options')
local current_window = api.nvim_get_current_win()
api.nvim_win_set_option(current_window, 'foldmethod', 'expr')
api.nvim_win_set_option(current_window, 'foldexpr', 'folding#foldexpr()')
end
local function get_comment_scopes(total_lines)
if not _NgConfigValues.ts_fold.comment then
return {}
end
local comment_scopes = {}
local comment_start = nil
total_lines = math.min(total_lines, _NgConfigValues.ts_fold.max_lines_scan_comments)
for line = 0, total_lines - 1 do
if is_comment(line + 1) then
if not comment_start then
comment_start = line
end
elseif comment_start then
if line - comment_start > 2 then -- More than 2 lines
table.insert(comment_scopes, { comment_start, line })
end
comment_start = nil
end
end
-- Handle case where file ends with a multiline comment
if comment_start and total_lines - comment_start > 2 then
table.insert(comment_scopes, { comment_start, total_lines })
end
trace(comment_scopes)
return comment_scopes
end
local function indent_levels(scopes, total_lines)
-- This is cached on buf tick to avoid computing that multiple times
-- Especially not for every line in the file when `zx` is hit
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local max_fold_level = api.nvim_win_get_option(0, 'foldnestmax')
local trim_level = function(level)
if level > max_fold_level then
@ -222,43 +58,10 @@ local function indent_levels(scopes, total_lines)
return level
end
local events = {}
local prev = { -1, -1 }
for _, scope in ipairs(scopes) do
if not (prev[1] == scope[1] and prev[2] == scope[2]) then
events[scope[1]] = (events[scope[1]] or 0) + 1 -- incase there is a fold inside a fold
events[scope[2]] = (events[scope[2]] or 0) - 1
end
prev = scope
end
trace(events)
local current_indent = 0
local indent_lvls = {}
local prev_indent_lvl = 0
local levels = {}
for line = 0, total_lines - 1 do
if events[line] then
current_indent = current_indent + events[line]
end
indent_lvls[line] = current_indent
local indent_symbol = indent_lvls[line] > prev_indent_lvl and '>' or ''
trace('Line ' .. line .. ': ' .. indent_symbol .. indent_lvls[line])
levels[line + 1] = indent_symbol .. tostring(trim_level(indent_lvls[line]))
prev_indent_lvl = indent_lvls[line]
end
trace(levels)
return levels
end
-- This is cached on buf tick to avoid computing that multiple times
-- Especially not for every line in the file when `zx` is hit
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local parser = parsers.get_parser(bufnr)
if not parser then
log('treesitter parser not loaded')
warn('treesitter parser not loaded')
return {}
end
@ -271,24 +74,16 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
end)
-- start..stop is an inclusive range
---@type table<number, number>
local start_counts = {}
---@type table<number, number>
local stop_counts = {}
local prev_start = -1
local prev_stop = -1
local min_fold_lines = api.nvim_win_get_option(0, 'foldminlines')
local scopes = {}
for _, match in ipairs(matches) do
local start, stop, stop_col ---@type integer, integer, integer
if match.metadata and match.metadata.range then
start, _, stop, stop_col = unpack(match.metadata.range) ---@type integer, integer, integer, integer
else
start, _, stop, stop_col = match.node:range() ---@type integer, integer, integer, integer
end
for _, node in ipairs(matches) do
local start, _, stop, stop_col = node.node:range()
if stop_col == 0 then
stop = stop - 1
@ -296,28 +91,71 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local fold_length = stop - start + 1
local should_fold = fold_length > min_fold_lines
-- Fold only multiline nodes that are not exactly the same as previously met folds
-- Checking against just the previously found fold is sufficient if nodes
-- are returned in preorder or postorder when traversing tree
if should_fold and not (start == prev_start and stop == prev_stop) then
start_counts[start] = (start_counts[start] or 0) + 1
stop_counts[stop] = (stop_counts[stop] or 0) + 1
-- trace('fold scope', start, stop, match.node:type())
prev_start = start
prev_stop = stop
table.insert(scopes, { start, stop })
end
end
local total_lines = api.nvim_buf_line_count(bufnr)
local comment_scopes = get_comment_scopes(total_lines)
scopes = vim.list_extend(scopes, comment_scopes)
table.sort(scopes, function(a, b)
if a[1] == b[1] then
return a[2] < b[2]
local levels = {}
local current_level = 0
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
for lnum = 0, api.nvim_buf_line_count(bufnr) do
local node, _ = get_node_at_line(lnum + 1)
-- log(lnum, node:type())
local comment = node:type() == 'comment'
local last_trimmed_level = trim_level(current_level)
current_level = current_level + (start_counts[lnum] or 0)
local trimmed_level = trim_level(current_level)
current_level = current_level - (stop_counts[lnum] or 0)
local next_trimmed_level = trim_level(current_level)
if comment then
if lnum == 0 or levels[lnum] == tostring(trimmed_level) then
levels[lnum + 1] = '>' .. tostring(trimmed_level + 1) -- allow comment fold independtly
else
levels[lnum + 1] = tostring(trimmed_level + 1) -- allow comment fold independtly
end
else
-- Determine if it's the start/end of a fold
-- NB: vim's fold-expr interface does not have a mechanism to indicate that
-- two (or more) folds start at this line, so it cannot distinguish between
-- ( \n ( \n )) \n (( \n ) \n )
-- versus
-- ( \n ( \n ) \n ( \n ) \n )
-- If it did have such a mechansim, (trimmed_level - last_trimmed_level)
-- would be the correct number of starts to pass on.
levels[lnum + 1] = tostring(trimmed_level)
if trimmed_level - last_trimmed_level > 0 then
levels[lnum + 1] = tostring(trimmed_level) -- hack
levels[lnum + 2] = '>' .. tostring(trimmed_level + 1) -- dirty hack
elseif trimmed_level - next_trimmed_level > 0 then
-- Ending marks tend to confuse vim more than it helps, particularly when
-- the fold level changes by at least 2; we can uncomment this if
-- vim's behavior gets fixed.
if lnum ~= 0 then
levels[lnum] = tostring(trimmed_level + 1)
end
levels[lnum + 1] = tostring(trimmed_level)
else
-- if levels[lnum + 1] == nil then
levels[lnum + 1] = tostring(trimmed_level + 1)
-- end
end
end
return a[1] < b[1]
end)
return indent_levels(scopes, total_lines)
end
log(levels)
return levels
end)
function M.get_fold_indic(lnum)
@ -327,7 +165,7 @@ function M.get_fold_indic(lnum)
local buf = api.nvim_get_current_buf()
local shown = false
for i = 1, vim.fn.tabpagenr('$') do
for _, value in pairs(vim.fn.tabpagebuflist(i)) do
for key, value in pairs(vim.fn.tabpagebuflist(i)) do
if value == buf then
shown = true
end
@ -337,7 +175,8 @@ function M.get_fold_indic(lnum)
return '0'
end
local levels = folds_levels(buf) or {}
-- trace(lnum, levels[lnum]) -- TODO: comment it out in master
-- log(lnum, levels[lnum]) -- TODO: comment it out in master
return levels[lnum] or '0'
end

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

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

@ -1,56 +0,0 @@
local M = {}
local util = require('navigator.util')
local log = util.log
local health = vim.health
if not vim.health then
health = require('health')
end
local nvim_09 = vim.fn.has('nvim-0.9') == 1
local start = nvim_09 and health.start or health.report_start
local ok = nvim_09 and health.ok or health.report_ok
local error = nvim_09 and health.error or health.report_error
local warn = nvim_09 and health.warn or health.report_warn
local info = nvim_09 and health.info or health.report_info
local vfn = vim.fn
local function plugin_check()
start('navigator Plugin Check')
local plugins = {
'lspconfig',
'nvim-treesitter',
'guihua',
}
local any_warn = false
local ts_installed = false
for _, plugin in ipairs(plugins) do
if pcall(require, plugin) then
ok(string.format('%s: plugin is installed', plugin))
if plugin == 'nvim-treesitter' then
ts_installed = true
end
else
any_warn = true
warn(string.format('%s: not installed/loaded', plugin))
end
end
if any_warn then
warn('Not all plugin installed')
else
ok('All plugin installed')
end
end
function M.check()
if vim.fn.has('nvim-0.9') == 0 then
warn('Suggested neovim version 0.9 or higher')
end
plugin_check()
end
return M

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

@ -1,41 +0,0 @@
local lsp = vim.lsp
local util = lsp.util
local nutils = require('navigator.util')
local api = vim.api
local log = nutils.log
local M = {}
function M.handler(err, result, ctx, config)
config = config or {}
config.focus_id = ctx.method
if err then
return vim.notify('no hover info ' .. err)
end
if api.nvim_get_current_buf() ~= ctx.bufnr then
-- Ignore result since buffer changed. This happens for slow language servers.
return
end
if not (result and result.contents) then
if config.silent ~= true then
vim.notify('No hover information available')
end
return
end
local format = 'markdown'
local contents ---@type string[]
if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then
format = 'plaintext'
contents = vim.split(result.contents.value or '', '\n', { trimempty = true })
else
contents = util.convert_input_to_markdown_lines(result.contents)
end
if vim.tbl_isempty(contents) then
if config.silent ~= true then
vim.notify('No information available')
end
return
end
return util.open_floating_preview(contents, format, config)
end
return M

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

@ -1,48 +1,64 @@
return {
init = function()
local loader = nil
local log = require('navigator.util').log
local packer_plugins = packer_plugins or nil -- suppress warnings
local log = require'navigator.util'.log
-- packer only
local lazy_plugins = {
['nvim-lspconfig'] = 'neovim/nvim-lspconfig',
['guihua.lua'] = 'ray-x/guihua.lua',
}
if pcall(require, 'lazy') then
require('lazy').load({ plugins = { 'nvim-lspconfig', 'guihua.lua' } })
elseif vim.fn.empty(packer_plugins) == 0 then -- packer install
if packer_plugins ~= nil then -- packer install
local lazy_plugins = {
["nvim-lspconfig"] = "neovim/nvim-lspconfig",
["guihua.lua"] = "ray-x/guihua.lua"
}
if _NgConfigValues.lsp_installer == true then
lazy_plugins["nvim-lsp-installer"] = "williamboman/nvim-lsp-installer"
end
-- packer installed
loader = require('packer').loader
loader = require"packer".loader
for plugin, url in pairs(lazy_plugins) do
if not packer_plugins[url] or not packer_plugins[url].loaded then
-- log("loading ", plugin)
loader(plugin)
end
end
else
loader = function(plugin)
local cmd = 'packadd ' .. plugin
vim.cmd(cmd)
end
if _NgConfigValues.lsp_installer == true then
local has_lspinst, lspinst = pcall(require, "lsp_installer")
log('lsp_installer installed', has_lspinst)
if has_lspinst then
lspinst.setup()
local configs = require "lspconfig/configs"
local servers = require'nvim-lsp-installer'.get_installed_servers()
for _, server in pairs(servers) do
local cfg = require'navigator.lspclient.clients'.get_cfg(server)
local lsp_inst_cfg = configs[server]
if lsp_inst_cfg and lsp_inst_cfg.document_config.default_config then
lsp_inst_cfg = lsp_inst_cfg.document_config.default_config
lsp_inst_cfg = vim.tbl_deep_extend('keep', lsp_inst_cfg, cfg)
require'lspconfig'[server].setup(lsp_inst_cfg)
end
end
end
end
end,
load = function(plugin_name, path)
local loader = nil
if pcall(require, 'lazy') then
require('lazy').load({ plugins = { plugin_name } })
else
packer_plugins = packer_plugins or nil -- suppress warnings
-- packer only
if packer_plugins ~= nil then -- packer install
local lazy_plugins = {}
lazy_plugins[plugin_name] = path
loader = require('packer').loader
for plugin, _ in pairs(lazy_plugins) do
if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then
pcall(loader, plugin)
end
local packer_plugins = packer_plugins or nil -- suppress warnings
-- packer only
if packer_plugins ~= nil then -- packer install
local lazy_plugins = {}
lazy_plugins[plugin_name] = path
loader = require"packer".loader
for plugin, url in pairs(lazy_plugins) do
if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then
-- log("loading ", plugin)
pcall(loader, plugin)
end
end
end
end,
end
}

@ -4,14 +4,19 @@ local lsp = require('vim.lsp')
local util = require('navigator.util')
local log = util.log
local trace = util.trace
_NG_Attached = {}
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 = {}
M.on_attach = function(client, bufnr)
bufnr = bufnr or 0
if bufnr == 0 then
vim.notify('no bufnr provided from LSP ' .. client.name, vim.log.levels.DEBUG)
vim.notify('no bufnr provided from LSP ', client.name)
end
local uri = vim.uri_from_bufnr(bufnr)
@ -23,25 +28,21 @@ M.on_attach = function(client, bufnr)
log('attaching: ', bufnr, client.name, uri)
trace(client)
_NG_Attached[client.name] = true
diagnostic_map(bufnr)
-- add highlight for Lspxxx
require('navigator.lspclient.highlight').add_highlight()
require('navigator.lspclient.highlight').config_signs()
require('navigator.lspclient.highlight').diagnositc_config_sign()
api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
require('navigator.lspclient.mapping').setup({
client = client,
bufnr = bufnr,
cap = client.resolved_capabilities,
})
if client.server_capabilities.documentHighlightProvider == true then
trace('attaching doc highlight: ', bufnr, client.name)
vim.defer_fn(function()
require('navigator.dochighlight').documentHighlight(bufnr)
end, 50) -- allow a bit time for it to settle down
else
log('skip doc highlight: ', bufnr, client.name)
if client.resolved_capabilities.document_highlight then
require('navigator.dochighlight').documentHighlight()
end
require('navigator.lspclient.lspkind').init()
@ -52,36 +53,15 @@ M.on_attach = function(client, bufnr)
log(client.name, 'customized attach for all clients')
config.on_attach(client, bufnr)
end
if config.lsp and config.lsp[client.name] then
if type(config.lsp[client.name]) == 'function' then
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
--- if code lens enabled
if _NgConfigValues.lsp.code_lens_action.enable then
if client.server_capabilities.codeLensProvider then
require('navigator.codelens').setup(bufnr)
end
if config.lsp and config.lsp[client.name] and config.lsp[client.name].on_attach ~= nil then
log('lsp client specific attach for', client.name)
config.lsp[client.name].on_attach(client, bufnr)
end
if _NgConfigValues.lsp.code_action.enable then
if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then
trace('code action enabled for client', client.server_capabilities.codeActionProvider)
api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
group = api.nvim_create_augroup('NGCodeActGroup_' .. tostring(bufnr), {}),
buffer = bufnr,
callback = function()
require('navigator.codeAction').code_action_prompt(bufnr)
end,
})
if client.resolved_capabilities.code_action then
log('code action enabled for client', client.resolved_capabilities.code_action)
vim.cmd([[autocmd CursorHold,CursorHoldI <buffer> lua require'navigator.codeAction'.code_action_prompt()]])
end
end
end

File diff suppressed because it is too large Load Diff

@ -1,215 +0,0 @@
local M = {}
local vfn = vim.fn
M.defaults = function()
local has_lsp, lspconfig = pcall(require, 'lspconfig')
local highlight = require('navigator.lspclient.highlight')
if not has_lsp then
return {
setup = function()
vim.notify('loading lsp config failed LSP may not working correctly', vim.log.levels.WARN)
end,
}
end
local util = lspconfig.util
local on_attach = require('navigator.lspclient.attach').on_attach
local setups = {
clojure_lsp = {
root_dir = function(fname)
return util.root_pattern(
'deps.edn',
'build.boot',
'project.clj',
'shadow-cljs.edn',
'bb.edn',
'.git'
)(fname) or util.path.dirname(fname)
end,
on_attach = on_attach,
filetypes = { 'clojure', 'edn' },
message_level = vim.lsp.protocol.MessageType.error,
cmd = { 'clojure-lsp' },
},
elixirls = {
on_attach = on_attach,
filetypes = { 'elixir', 'eelixir' },
cmd = { 'elixir-ls' },
message_level = vim.lsp.protocol.MessageType.error,
settings = {
elixirLS = {
dialyzerEnabled = true,
fetchDeps = false,
},
},
root_dir = function(fname)
return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname)
end,
},
gopls = {
-- capabilities = cap,
filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' },
message_level = vim.lsp.protocol.MessageType.Error,
cmd = {
'gopls', -- share the gopls instance if there is one already
'-remote=auto', --[[ debug options ]] --
-- "-logfile=auto",
-- "-debug=:0",
'-remote.debug=:0',
-- "-rpc.trace",
},
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
settings = {
gopls = {
-- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md
-- flags = {allow_incremental_sync = true, debounce_text_changes = 500},
-- not supported
analyses = { unusedparams = true, unreachable = false },
codelenses = {
generate = true, -- show the `go generate` lens.
gc_details = true, -- // Show a code lens toggling the display of gc's choices.
test = true,
tidy = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
matcher = 'fuzzy',
diagnosticsDelay = '500ms',
symbolMatcher = 'fuzzy',
gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils
buildFlags = { '-tags', 'integration' },
-- buildFlags = {"-tags", "functional"}
semanticTokens = true,
},
},
on_attach = function(client, bufnr)
on_attach(client, bufnr)
if
vim.fn.has('nvim-0.8.3') == 1
and not client.server_capabilities.semanticTokensProvider
then
local semantic = client.config.capabilities.textDocument.semanticTokens
if semantic then
client.server_capabilities.semanticTokensProvider = {
full = true,
legend = {
tokenModifiers = semantic.tokenModifiers,
tokenTypes = semantic.tokenTypes,
},
range = true,
}
end
end
end,
root_dir = function(fname)
return util.root_pattern('go.mod', '.git')(fname) or util.path.dirname(fname)
end,
},
clangd = {
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
cmd = {
'clangd',
'--background-index',
'--suggest-missing-includes',
'--clang-tidy',
'--header-insertion=iwyu',
'--enable-config',
'--offset-encoding=utf-16',
'--clang-tidy-checks=-*,llvm-*,clang-analyzer-*',
'--cross-file-rename',
},
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
on_attach = function(client, bufnr)
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or true
on_attach(client, bufnr)
end,
},
rust_analyzer = {
root_dir = function(fname)
return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname)
or util.path.dirname(fname)
end,
filetypes = { 'rust' },
message_level = vim.lsp.protocol.MessageType.error,
on_attach = on_attach,
settings = {
['rust-analyzer'] = {
cargo = { loadOutDirsFromCheck = true },
procMacro = { enable = true },
},
},
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
},
sqlls = {
cmd = { 'sql-language-server', 'up', '--method', 'stdio' },
filetypes = { 'sql', 'mysql' },
root_dir = util.root_pattern('.sqllsrc.json'),
on_attach = on_attach,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
},
pyright = {
on_attach = on_attach,
-- on_init = require('navigator.lspclient.python').on_init,
on_init = function(client)
require('navigator.lspclient.python').on_init(client)
end,
on_new_config = function(new_config, new_root_dir)
local python_path = require('navigator.lspclient.python').pyenv_path(new_root_dir)
new_config.settings.python.pythonPath = python_path
end,
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
python = {
venvPath = '.',
formatting = { provider = 'black' },
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = 'workspace',
},
},
},
},
ccls = {
on_attach = on_attach,
init_options = {
compilationDatabaseDirectory = 'build',
root_dir = [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]],
index = { threads = 2 },
clang = { excludeArgs = { '-frounding-math' } },
},
flags = { allow_incremental_sync = true },
},
jdtls = {
settings = {
java = {
signatureHelp = { enabled = true },
contentProvider = { preferred = 'fernflower' },
},
},
},
omnisharp = {
cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vfn.getpid()) },
},
terraformls = {
filetypes = { 'terraform', 'tf' },
},
sourcekit = {
cmd = { 'sourcekit-lsp' },
filetypes = { 'swift' }, -- This is recommended if you have separate settings for clangd.
},
}
setups.lua_ls = require('navigator.lspclient.lua_ls').lua_ls()
return setups
end
return M

@ -1,11 +1,12 @@
local M = {}
local lsp = require("vim.lsp")
M = {}
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
function M.reload_lsp()
vim.cmd("LspStop")
local uv = vim.uv or vim.loop
local timer = uv.new_timer()
local timer = vim.loop.new_timer()
local i = 0
timer:start(500, 100, function()
if i >= 5 then

@ -1,67 +1,89 @@
local M = {}
-- local log = require('navigator.util').log
local log = require"navigator.util".log
local api = vim.api
local cmd_group = api.nvim_create_augroup('NGHiGroup', {})
-- lsp sign          ﮻         ﯭ        ﳀ  
function M.config_signs()
function M.diagnositc_config_sign()
if M.configed then
return
end
local icons = _NgConfigValues.icons
local sign_name = 'NavigatorLightBulb'
local sign_name = "NavigatorLightBulb"
if vim.fn.sign_getdefined(sign_name).text == nil then
vim.fn.sign_define(
sign_name,
{ text = icons.code_action_icon, texthl = 'LspDiagnosticsSignHint' }
)
sign_name = 'NavigatorCodeLensLightBulb'
vim.fn.sign_define(
sign_name,
{ text = icons.code_lens_action_icon, texthl = 'LspDiagnosticsSignHint' }
)
vim.fn
.sign_define(sign_name, {text = icons.code_action_icon, texthl = "LspDiagnosticsSignHint"})
sign_name = "NavigatorCodeLensLightBulb"
vim.fn.sign_define(sign_name,
{text = icons.code_lens_action_icon, texthl = "LspDiagnosticsSignHint"})
end
local e, w, i, h = icons.diagnostic_err, icons.diagnostic_warn, icons.diagnostic_info,
icons.diagnostic_hint
if vim.diagnostic ~= nil then
local t = vim.fn.sign_getdefined('DiagnosticSignWarn')
if vim.tbl_isempty(t) or t[1].text == "W " and icons.icons == true then
vim.fn.sign_define('DiagnosticSignError',
{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')
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
M.configed = true
end
local colors = {
{ '#aefe00', '#aede00', '#aebe00', '#4e7efe' },
{ '#ff00e0', '#df00e0', '#af00e0', '#fedefe' },
{ '#1000ef', '#2000df', '#2000cf', '#f0f040' },
{ '#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33' },
{ '#ffa724', '#efa024', '#dfa724', '#0040ff' },
{ '#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f' },
}
function M.add_highlight()
-- lsp system default
api.nvim_command("hi! link LspDiagnosticsUnderlineError SpellBad")
api.nvim_command("hi! link LspDiagnosticsUnderlineWarning SpellRare")
api.nvim_command("hi! link LspDiagnosticsUnderlineInformation SpellRare")
api.nvim_command("hi! link LspDiagnosticsUnderlineHint SpellRare")
api.nvim_set_hl(0, 'DiagnosticUnderlineError', { link = 'SpellBad', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineWarn', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineInfo', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineHint', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'NGPreviewTitle', { link = 'Title', default = true })
api.nvim_set_hl(0, 'LspReferenceRead', { default = true, link = 'IncSearch' })
api.nvim_set_hl(0, 'LspReferenceText', { default = true, link = 'Visual' })
api.nvim_set_hl(0, 'LspReferenceWrite', { default = true, link = 'Search' })
api.nvim_command("hi! link DiagnosticUnderlineError SpellBad")
api.nvim_command("hi! link DiagnosticUnderlineWarning SpellRare")
api.nvim_command("hi! link DiagnosticUnderlineInformation SpellRare")
api.nvim_command("hi! link DiagnosticUnderlineHint SpellRare")
api.nvim_command("hi def link NGPreviewTitle Title")
local colors = {
{'#aefe00', '#aede00', '#aebe00', '#4e7efe'}, {'#ff00e0', '#df00e0', '#af00e0', '#fedefe'},
{'#1000ef', '#2000df', '#2000cf', '#f0f040'}, {'#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33'},
{'#ffa724', '#efa024', '#dfa724', '#0040ff'}, {'#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f'}
}
for i = 1, #colors do
for j = 1, 3 do
local hlg = string.format('NGHiReference_%i_%i', i, j) -- , colors[i][j], colors[i][4]
api.nvim_set_hl(0, hlg, { fg = colors[i][j], bg = colors[i][4], default = true })
local cmd = string.format("hi! default NGHiReference_%i_%i guibg=%s guifg=%s ", i, j,
colors[i][j], colors[i][4])
vim.cmd(cmd)
end
end
end
api.nvim_create_autocmd('ColorScheme', {
group = cmd_group,
pattern = '*',
callback = function()
M.add_highlight()
end,
})
return M

@ -1,68 +0,0 @@
local log = require('vim.lsp.log')
local util = require('vim.lsp.util')
local api = vim.api
local bufstates = {}
return {
on_inlayhint = function(err, result, ctx, _)
if err then
if log.error() then
log.error('inlayhint', err)
end
return
end
local bufnr = assert(ctx.bufnr)
if util.buf_versions[bufnr] ~= ctx.version then
return
end
local client_id = ctx.client_id
if not result then
return
end
local bufstate = bufstates[bufnr]
if not bufstate or not bufstate.enabled then
return
end
if not (bufstate.client_hint and bufstate.version) then
bufstate.client_hint = vim.defaulttable()
bufstate.version = ctx.version
end
local hints_by_client = bufstate.client_hint
local client = assert(vim.lsp.get_client_by_id(client_id))
local new_hints_by_lnum = vim.defaulttable()
local num_unprocessed = #result
if num_unprocessed == 0 then
hints_by_client[client_id] = {}
bufstate.version = ctx.version
api.nvim__buf_redraw_range(bufnr, 0, -1)
return
end
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
---@param position lsp.Position
---@return integer
local function pos_to_byte(position)
local col = position.character
if col > 0 then
local line = lines[position.line + 1] or ''
local ok, convert_result
ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding)
if ok then
return convert_result
end
return math.min(#line, col)
end
return col
end
for _, hint in ipairs(result) do
local lnum = hint.position.line
hint.position.character = pos_to_byte(hint.position)
table.insert(new_hints_by_lnum[lnum], hint)
end
hints_by_client[client_id] = new_hints_by_lnum
bufstate.version = ctx.version
api.nvim__buf_redraw_range(bufnr, 0, -1)
end,
}

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

@ -1,68 +0,0 @@
local vfn = vim.fn
local on_attach = require('navigator.lspclient.attach').on_attach
local library = {}
local function add(lib)
for _, p in pairs(vfn.expand(lib, false, true)) do
local uv = vim.uv or vim.loop
p = uv.fs_realpath(p)
if p then
library[p] = true
end
end
end
local function lua_ls()
-- add runtime
-- add plugins it may be very slow to add all in path
add('$VIMRUNTIME')
-- add your config
-- local home = vfn.expand("$HOME")
add(vfn.stdpath('config'))
library[vfn.expand('$VIMRUNTIME/lua')] = true
library[vfn.expand('$VIMRUNTIME/lua/vim')] = true
library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true
return {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
on_attach = on_attach,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
},
hint = { enable = true, typeCoverage = true },
diagnostics = {
enable = true,
-- Get the language server to recognize the `vim` global
globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' },
},
completion = { callSnippet = 'Both' },
workspace = {
-- Make the server aware of Neovim runtime files
library = library,
checkThirdParty = false,
maxPreload = 1000,
preloadFileSize = 40000,
},
telemetry = { enable = false },
},
},
on_new_config = function(cfg, root)
local libs = vim.schedule(function()
vim.tbl_deep_extend('force', {}, library)
end)
libs[root] = nil
cfg.settings.Lua.workspace.library = libs
return cfg
end,
}
end
return {
lua_ls = lua_ls,
}

@ -1,127 +1,81 @@
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local api = vim.api
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 function fallback_keymap(key)
-- when handler failed fallback to key
vim.schedule(function()
print('fallback to key', key)
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), 'n', true)
end)
end
local function fallback_fn(key)
return function()
fallback_keymap(key)
end
end
local log = require('navigator.util').log
local trace = require('navigator.util').trace
local event_hdlrs = {
{ ev = 'BufWritePre', func = [[require "navigator.diagnostics".set_diag_loclist()]] },
{ ev = 'CursorHold', func = 'document_highlight()' },
{ ev = 'CursorHoldI', func = 'document_highlight()' },
{ ev = 'CursorMoved', func = 'clear_references()' },
}
local double = { '', '', '', '', '', '', '', '' }
local single = { '', '', '', '', '', '', '', '' }
local remap = util.binding_remap
-- stylua: ignore start
-- TODO https://github.com/neovim/neovim/pull/16591 use vimkeymap.set/del
-- LuaFormatter off
local key_maps = {
{ key = 'gr', func = require('navigator.reference').async_ref, desc = 'async_ref' },
{ key = '<Leader>gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated
{ mode = 'i', key = '<M-k>', func = vim.lsp.buf.signature_help, desc = 'signature_help' },
{ key = '<c-k>', func = vim.lsp.buf.signature_help, desc = 'signature_help' },
{ key = '<Leader>g0', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' },
{ key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' },
{ key = '<c-]>', func = require('navigator.definition').definition, desc = 'definition' },
{ key = 'gd', func = remap(require('navigator.definition').definition, 'gd'), desc = 'definition' },
{ key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration', fallback = fallback_fn('gD') }, -- fallback used
-- for lsp handler
{ key = 'gp', func = remap(require('navigator.definition').definition_preview, 'gp'), desc = 'definition_preview' }, -- paste
{ key = 'gP', func = remap(require('navigator.definition').type_definition_preview, 'gP'), desc = 'type_definition_preview' }, -- paste
{ key = '<Leader>gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' },
{ key = '<Leader>gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' },
{ key = '<Leader>ct', func = require('navigator.ctags').ctags, desc = 'ctags' },
{ key = '<Space>ca', mode = 'n', func = require('navigator.codeAction').code_action, desc = 'code_action' },
{ key = '<Space>ca', mode = 'v', func = require('navigator.codeAction').range_code_action, desc = 'range_code_action' },
{ key = 'gr', func = "require('navigator.reference').reference()" },
{ key = 'Gr', func = "require('navigator.reference').async_ref()" },
{ mode = 'i', key = '<M-k>', func = 'signature_help()' },
{ key = '<c-k>', func = 'signature_help()' },
{ key = 'g0', func = "require('navigator.symbols').document_symbols()" },
{ key = 'gW', func = "require('navigator.workspace').workspace_symbol()" },
{ key = '<c-]>', func = "require('navigator.definition').definition()" },
{ key = 'gD', func = "declaration({ border = 'rounded', max_width = 80 })" },
{ key = 'gp', func = "require('navigator.definition').definition_preview()" },
{ key = '<Leader>gt', func = "require('navigator.treesitter').buf_ts()" },
{ key = '<Leader>gT', func = "require('navigator.treesitter').bufs_ts()" },
{ key = 'K', func = 'hover({ popup_opts = { border = single, max_width = 80 }})' },
{ key = '<Space>ca', mode = 'n', func = "require('navigator.codeAction').code_action()" },
{ key = '<Space>cA', mode = 'v', func = 'range_code_action()' },
-- { key = '<Leader>re', func = 'rename()' },
{ key = '<Space>rn', func = require('navigator.rename').rename, desc = 'rename' },
{ key = '<Leader>gi', func = vim.lsp.buf.incoming_calls, desc = 'incoming_calls' },
{ key = '<Leader>go', func = vim.lsp.buf.outgoing_calls, desc = 'outgoing_calls' },
{ key = 'gi', func = vim.lsp.buf.implementation, desc = 'implementation', fallback = fallback_fn('gi') }, -- insert
{ key = '<Space>D', func = vim.lsp.buf.type_definition, desc = 'type_definition' },
{ key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' },
{ key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' },
{ key = '<Leader>dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' },
{ key = ']d', func = require('navigator.diagnostics').goto_next, desc = 'next diagnostics error or fallback' },
{ key = '[d', func = require('navigator.diagnostics').goto_prev, desc = 'prev diagnostics error or fallback' },
{ key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' },
{ key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' },
{ key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' },
{ key = '<C-LeftMouse>', func = vim.lsp.buf.definition, desc = 'definition', fallback = fallback_fn('<C-LeftMouse>')},
{ key = 'g<LeftMouse>', func = vim.lsp.buf.implementation, desc = 'implementation' },
{ key = '<Leader>k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' },
{ key = '<Space>wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' },
{ key = '<Space>wr', func = require('navigator.workspace').remove_workspace_folder, desc = 'remove_workspace_folder' },
{ key = '<Space>ff', func = vim.lsp.buf.format, mode = 'n', desc = 'format' },
{ key = '<Space>ff', func = vim.lsp.buf.range_formatting, mode = 'v', desc = 'range format' },
{ key = '<Space>gm', func = require('navigator.formatting').range_format, mode = 'n', desc = 'range format operator e.g gmip' },
{ key = '<Space>wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' },
{
key = '<Space>la',
mode = 'n',
func = require('navigator.codelens').run_action,
desc = 'run code lens action',
}
-- stylua: ignore end
{ key = '<Space>rn', func = "require('navigator.rename').rename()" },
{ key = '<Leader>gi', func = 'incoming_calls()' },
{ key = '<Leader>go', func = 'outgoing_calls()' },
{ key = 'gi', func = 'implementation()' },
{ key = '<Space>D', func = 'type_definition()' },
{ key = 'gL', func = "require('navigator.diagnostics').show_diagnostics()" },
{ key = 'gG', func = "require('navigator.diagnostics').show_buf_diagnostics()" },
{ key = '<Leader>dt', func = "require('navigator.diagnostics').toggle_diagnostics()" },
{ key = ']d', func = "diagnostic.goto_next({ border = 'rounded', max_width = 80})" },
{ key = '[d', func = "diagnostic.goto_prev({ border = 'rounded', max_width = 80})" },
{ key = ']r', func = "require('navigator.treesitter').goto_next_usage()" },
{ key = '[r', func = "require('navigator.treesitter').goto_previous_usage()" },
{ key = '<C-LeftMouse>', func = 'definition()' },
{ key = 'g<LeftMouse>', func = 'implementation()' },
{ key = '<Leader>k', func = "require('navigator.dochighlight').hi_symbol()" },
{ key = '<Space>wa', func = "require('navigator.workspace').add_workspace_folder()" },
{ key = '<Space>wr', func = "require('navigator.workspace').remove_workspace_folder()" },
{ key = '<Space>ff', func = 'formatting()', mode = 'n' },
{ key = '<Space>ff', func = 'range_formatting()', mode = 'v' },
{ key = '<Space>wl', func = "require('navigator.workspace').list_workspace_folders()" },
{ key = '<Space>la', mode = 'n', func = "require('navigator.codelens').run_action()" },
}
if _NgConfigValues.lsp.hover then
table.insert(key_maps, { key = 'K', func = vim.lsp.buf.hover, desc = 'hover' })
end
local key_maps_help = {}
-- LuaFormatter on
local M = {}
local ccls_mappings = {
{
key = '<Leader>gi',
func = require('navigator.cclshierarchy').incoming_calls,
desc = 'incoming_calls',
},
{
key = '<Leader>go',
func = require('navigator.cclshierarchy').outgoing_calls,
desc = 'outgoing_calls',
},
{ key = '<Leader>gi', func = "require('navigator.cclshierarchy').incoming_calls()" },
{ key = '<Leader>go', func = "require('navigator.cclshierarchy').outgoing_calls()" },
}
local check_cap = function(opts)
-- log(vim.lsp.get_clients({buffer = 0}))
local check_cap = function(cap)
-- log(vim.lsp.buf_get_clients(0))
local fmt, rfmt, ccls
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
if cap and cap.document_formatting then
fmt = true
end
if cap and cap.documentRangeFormattingProvider then
if cap and cap.document_range_formatting then
rfmt = true
end
for _, value in pairs(vim.lsp.get_clients({ buffer = 0 })) do
for _, value in pairs(vim.lsp.buf_get_clients(0)) do
trace(value)
if value ~= nil and value.server_capabilities == nil then
if value.server_capabilities.documentFormattingProvider then
if value ~= nil and value.resolved_capabilities == nil then
if value.resolved_capabilities.document_formatting then
fmt = true
end
if value.server_capabilities.documentRangeFormattingProvider then
if value.resolved_capabilities.document_range_formatting then
rfmt = true
end
@ -134,52 +88,25 @@ local check_cap = function(opts)
return fmt, rfmt, ccls
end
local function set_cmds(_)
local commands = {
[[command! -nargs=* Nctags lua require("navigator.ctags").ctags(<f-args>)]],
"command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()",
"command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()",
"command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>",
"command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>",
"command! -nargs=0 LspSymbols lua require'navigator.symbols'.side_panel()<CR>",
"command! -nargs=0 TSymbols lua require'navigator.treesitter'.side_panel()<CR>",
"command! -nargs=0 NRefPanel lua require'navigator.reference'.side_panel()<CR>",
"command! -nargs=* Calltree lua require'navigator.hierarchy'.calltree(<f-args>)<CR>",
"command! -nargs=* TsAndDiag lua require'navigator.sidepanel'.treesitter_and_diag_panel(<f-args>)<CR>",
"command! -nargs=* LspAndDiag lua require'navigator.sidepanel'.lsp_and_diag_panel(<f-args>)<CR>",
}
for _, value in pairs(commands) do
vim.cmd(value)
end
end
-- should works for both 1)attach from known lsp client or from a disabled lsp client
-- executed in on_attach context
local function set_mapping(lsp_attach_info)
local function set_mapping(user_opts)
log('setup mapping')
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
user_opts = user_opts or {}
local user_key = _NgConfigValues.keymaps or {}
local bufnr = lsp_attach_info.bufnr or 0
local ks = {}
local function del_keymap(mode, key, ...)
local k = ks[mode]
if not k then
ks[mode] = vim.api.nvim_buf_get_keymap(bufnr, mode)
k = ks[mode]
end
if vim.tbl_contains(k, key) then
vim.api.nvim_buf_del_keymap(bufnr, mode, key)
end
local bufnr = user_opts.bufnr or 0
local function del_keymap(...)
vim.api.nvim_buf_del_keymap(bufnr, ...)
end
local doc_fmt, range_fmt, ccls = check_cap(lsp_attach_info)
local function set_keymap(...)
vim.api.nvim_buf_set_keymap(bufnr, ...)
end
-- local function buf_set_option(...)
-- vim.api.nvim_buf_set_option(bufnr, ...)
-- end
local doc_fmt, range_fmt, ccls = check_cap(user_opts.cap)
if ccls then
vim.list_extend(key_maps, ccls_mappings)
@ -190,12 +117,7 @@ local function set_mapping(lsp_attach_info)
trace('binding', v)
local exists = false
for _, default in pairs(key_maps) do
if
-- override only if func and mode are the same
v.func == default.func
and (v.mode or 'n') == (default.mode or 'n')
and not default.override
then
if v.func == default.func and (v.mode or 'n') == (default.mode or 'n') and not default.override then
default.key, default.override, exists = v.key, true, true
break
end
@ -205,119 +127,92 @@ local function set_mapping(lsp_attach_info)
end
end
else
-- disable default mapping
key_maps = _NgConfigValues.keymaps or {}
log('setting maps to ', key_maps)
end
local fmtkey, rfmtkey, nrfmtkey
local fmtkey, rfmtkey
for _, value in pairs(key_maps) do
if value.doc then
vim.notify('doc field no longer supported in navigator mapping, use desc instead')
end
if type(value.func) == 'function' then
-- neovim 0.7.0
opts.buffer = key_maps.buffer or value.buffer
if value.desc then
opts.desc = value.desc
end
opts.buffer = bufnr
vim.keymap.set(value.mode or 'n', value.key, value.func, opts)
if string.find(value.desc, 'range format') and value.mode == 'v' then
rfmtkey = value.key
if string.find(value.desc, 'range format') and value.mode == 'n' then
nrfmtkey = value.key
elseif string.find(value.desc, 'format') then
fmtkey = value.key
end
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
if string.find(value.func, 'require') then
f = '<Cmd>lua ' .. value.func .. '<CR>'
elseif string.find(value.func, 'diagnostic') then
local diagnostic = '<Cmd>lua vim.'
if vim.lsp.diagnostic ~= nil then
diagnostic = '<Cmd>lua vim.lsp.'
end
f = diagnostic .. value.func .. '<CR>'
elseif string.find(value.func, 'vim.') then
f = '<Cmd>lua ' .. value.func .. '<CR>'
end
end
for _, val in pairs(key_maps) do
local helper_msg = ''
if val.desc then
helper_msg = val.desc
elseif type(val.func) == 'string' then
helper_msg = val.func
local k = value.key
local m = value.mode or 'n'
if string.find(value.func, 'range_formatting') then
rfmtkey = value.key
elseif string.find(value.func, 'formatting') then
fmtkey = value.key
end
log('binding', k, f)
set_keymap(m, k, f, opts)
end
local item = (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg
if not vim.tbl_contains(key_maps_help, item) then
table.insert(key_maps_help, (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg)
end
for _, val in pairs(key_maps) do
table.insert(key_maps_help, (val.mode or 'n') .. '|' .. val.key .. '|' .. val.func)
end
-- if user_opts.cap.document_formatting then
if doc_fmt and _NgConfigValues.lsp.format_on_save then
local fos = _NgConfigValues.lsp.format_on_save
local gn = api.nvim_create_augroup('NavAuGroupFormat', {})
local fmt = false
if type(fos) == 'boolean' then
fmt = fos
end
if type(fos) == 'table' and (fos.enable or fos.disable) then
if fos.enable then
-- lsp.format_on_save = {enable = {"python"}}
fmt = vim.tbl_contains(fos.enable, vim.o.ft)
end
-- lsp.format_on_save = {disable = {"python"}}
if fos.disable then
fmt = not vim.tbl_contains(fos.disable, vim.o.ft)
end
end
if type(fos) == 'function' then
fmt = fos(bufnr)
end
local fopts = _NgConfigValues.lsp.format_options
if fopts.async == nil and vim.api.nvim_buf_line_count(0) > 4000 then
fopts.async = true
end
if fmt then
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = gn,
desc = 'auto format',
buffer = bufnr,
callback = function()
trace('format' .. vim.inspect(fopts))
vim.lsp.buf.format(fopts)
end,
})
end
vim.cmd([[
aug NavigatorAuFormat
au!
autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting()
aug END
]])
elseif fmtkey then
del_keymap('n', fmtkey)
end
if lsp_attach_info.cap and lsp_attach_info.cap.document_range_formatting then
log('formatting enabled', lsp_attach_info.cap)
if user_opts.cap.document_range_formatting then
log('formatting enabled', user_opts.cap)
end
if not range_fmt and rfmtkey then
del_keymap('v', rfmtkey)
end
if not range_fmt and nrfmtkey then
del_keymap('n', nrfmtkey)
end
log('enable format ', doc_fmt, range_fmt, _NgConfigValues.lsp.format_on_save)
log('enable format ', doc_fmt, range_fmt)
end
local function autocmd()
local gn = api.nvim_create_augroup('NavAuGroupDocHlAu', {})
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = gn,
desc = 'doc highlight',
callback = require('navigator.dochighlight').cmd_nohl,
})
local function autocmd(user_opts)
vim.api.nvim_exec(
[[
aug NavigatorDocHlAu
au!
au CmdlineLeave : lua require('navigator.dochighlight').cmd_nohl()
aug END
]],
false
)
end
api.nvim_create_autocmd({ 'CmdlineLeave' }, {
group = gn,
desc = 'doc highlight nohl',
callback = require('navigator.dochighlight').cmd_nohl,
})
local function set_event_handler(user_opts)
user_opts = user_opts or {}
local file_types =
'c,cpp,h,go,python,vim,sh,javascript,html,css,lua,typescript,rust,javascriptreact,typescriptreact,json,yaml,kotlin,php,dart,nim,terraform,java'
-- local format_files = "c,cpp,h,go,python,vim,javascript,typescript" --html,css,
vim.api.nvim_command([[augroup nvim_lsp_autos]])
vim.api.nvim_command([[autocmd!]])
for _, value in pairs(event_hdlrs) do
local f = ''
if string.find(value.func, 'require') ~= nil then
f = 'lua ' .. value.func
else
f = 'lua vim.lsp.buf.' .. value.func
end
local cmd = 'autocmd FileType ' .. file_types .. ' autocmd nvim_lsp_autos ' .. value.ev .. ' <buffer> silent! ' .. f
vim.api.nvim_command(cmd)
end
vim.api.nvim_command([[augroup END]])
end
M.toggle_lspformat = function(on)
@ -328,134 +223,65 @@ M.toggle_lspformat = function(on)
end
if _NgConfigValues.lsp.format_on_save then
if on == nil then
vim.notify('format on save true', vim.log.levels.INFO)
vim.notify('format on save true', vim.lsp.log_levels.INFO)
end
vim.cmd([[set eventignore-=BufWritePre]])
else
if on == nil then
vim.notify('format on save false', vim.log.levels.INFO)
vim.notify('format on save false', vim.lsp.log_levels.INFO)
end
vim.cmd([[set eventignore+=BufWritePre]])
end
end
function M.setup(attach_opts)
if not attach_opts or not attach_opts.client then
vim.notify(
'please call require"navigator.mapping".setup({bufnr=bufnr, client=client}) inside on_attach(client,bufnr)',
vim.log.levels.WARN
)
end
attach_opts = attach_opts or { bufnr = 0, client = {}, cap = {} }
set_mapping(attach_opts)
set_cmds(attach_opts)
autocmd()
local client = attach_opts.client or {}
local cap = client.server_capabilities
if cap == nil then
log('no cap found for client ', client.name)
return
end
function M.setup(user_opts)
user_opts = user_opts or _NgConfigValues
set_mapping(user_opts)
log('lsp cap:', cap.codeActionProvider)
if
_NgConfigValues.lsp.call_hierarchy.enable and cap.call_hierarchy or cap.callHierarchyProvider
then
vim.lsp.handlers['callHierarchy/incomingCalls'] =
require('navigator.hierarchy').incoming_calls_handler
vim.lsp.handlers['callHierarchy/outgoingCalls'] =
require('navigator.hierarchy').outgoing_calls_handler
end
autocmd(user_opts)
set_event_handler(user_opts)
if _NgConfigValues.lsp.definition.enable then
for _, value in pairs(key_maps) do
if value.func == vim.lsp.buf.definition then
vim.lsp.handlers['textDocument/definition'] = util.mk_handler_remap(
require('navigator.definition').definition_handler, value.fallback)
end
local cap = user_opts.cap or vim.lsp.protocol.make_client_capabilities()
log('lsp cap:', cap)
if value.func == vim.lsp.buf.type_definition then
vim.lsp.handlers['textDocument/typeDefinition'] = util.mk_handler_remap(
require('navigator.definition').definition_handler, value.fallback)
end
end
else
-- delete keymaps
for _, value in pairs(key_maps) do
if value.func == vim.lsp.buf.definition or value.func == vim.lsp.buf.type_definition then
vim.keymap.del(value.mode or 'n', value.key, { buffer = attach_opts.bufnr or vim.api.nvim_get_current_buf() })
end
end
if cap.call_hierarchy or cap.callHierarchy then
vim.lsp.handlers['callHierarchy/incomingCalls'] = require('navigator.hierarchy').incoming_calls_handler
vim.lsp.handlers['callHierarchy/outgoingCalls'] = require('navigator.hierarchy').outgoing_calls_handler
end
vim.lsp.handlers['textDocument/references'] = require('navigator.reference').reference_handler
-- vim.lsp.handlers["textDocument/codeAction"] = require"navigator.codeAction".code_action_handler
vim.lsp.handlers['textDocument/definition'] = require('navigator.definition').definition_handler
if cap.declarationProvider then
local hdlr = require('navigator.definition').declaration_handler
for _, value in pairs(key_maps) do
if value.func == vim.lsp.buf.declaration then
vim.lsp.handlers['textDocument/declaration'] = util.mk_handler_remap(hdlr, value.fallback)
break
end
end
else
-- remove declaration keymap
for _, value in pairs(key_maps) do
if value.func == vim.lsp.buf.declaration then
vim.keymap.del(value.mode or 'n', value.key, { buffer = attach_opts.bufnr or vim.api.nvim_get_current_buf() })
break
end
end
if cap.declaration then
vim.lsp.handlers['textDocument/declaration'] = require('navigator.definition').declaration_handler
end
if _NgConfigValues.lsp.implementation.enable then
vim.lsp.handlers['textDocument/implementation'] =
require('navigator.implementation').implementation_handler
end
vim.lsp.handlers['textDocument/typeDefinition'] = require('navigator.definition').typeDefinition_handler
vim.lsp.handlers['textDocument/implementation'] = require('navigator.implementation').implementation_handler
-- vim.lsp.handlers['textDocument/documentSymbol'] = require('navigator.symbols').document_symbol_handler
if _NgConfigValues.lsp.workspace.enable then
vim.lsp.handlers['workspace/symbol'] = require('navigator.symbols').workspace_symbol_handler
end
if _NgConfigValues.lsp.diagnostic.enable then
vim.lsp.handlers['textDocument/publishDiagnostics'] =
require('navigator.diagnostics').diagnostic_handler
end
vim.lsp.handlers['workspace/symbol'] = require('navigator.symbols').workspace_symbol_handler
vim.lsp.handlers['textDocument/publishDiagnostics'] = require('navigator.diagnostics').diagnostic_handler
-- TODO: when active signature merge to neovim, remove this setup:
if
vim.fn.empty(_NgConfigValues.signature_help_cfg) == 0 or _NgConfigValues.lsp_signature_help
_NgConfigValues.signature_help_cfg and #_NgConfigValues.signature_help_cfg > 0 or _NgConfigValues.lsp_signature_help
then
log('setup signature from navigator')
local hassig, sig = pcall(require, 'lsp_signature')
if hassig then
sig.setup(_NgConfigValues.signature_help_cfg or {})
end
end
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = api.nvim_create_augroup('nvim_nv_event_autos', {}),
buffer = attach_opts.bufnr,
desc = 'diagnostic update',
callback = function()
require('navigator.diagnostics').setloclist(attach_opts.bufnr)
end,
})
local border_style = single
if _NgConfigValues.border == 'double' then
border_style = double
end
if _NgConfigValues.lsp.hover.enable then
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(require('navigator.hover').handler, {
border = border_style,
else
vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(require('navigator.signature').signature_handler, {
border = { '', '', '', '', '', '', '', '' },
})
end
if cap.documentFormattingProvider then
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = single })
if cap.document_formatting then
log('formatting enabled setup hdl')
vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl
end
@ -468,7 +294,7 @@ M.get_keymaps_help = function()
border = 'none',
prompt = true,
enter = true,
rect = { height = 24, width = 50 },
rect = { height = 20, width = 90 },
data = key_maps_help,
})

@ -1,39 +0,0 @@
local util = require('lspconfig/util')
local path = util.path
local M = {}
local shell = vim.o.shell
local exepath = vim.fn.exepath
-- https://github.com/ray-x/navigator.lua/issues/247#issue-1465308677
M.pyenv_path = function(workspace)
-- Use activated virtualenv.
if vim.env.VIRTUAL_ENV then
return path.join(vim.env.VIRTUAL_ENV, 'bin', 'python'), 'virtual env'
end
-- Find and use virtualenv in workspace directory.
for _, pattern in ipairs({ '*', '.*' }) do
local match = vim.fn.glob(path.join(workspace, pattern, 'pyvenv.cfg'))
local sep = require('navigator.util').path_sep()
local py = 'bin' .. sep .. 'python'
if match ~= '' then
print('found', match)
print(vim.fn.glob(path.join(workspace, pattern)))
match = string.gsub(match, 'pyvenv.cfg', py)
return match, string.format('venv base folder: %s', match)
end
match = vim.fn.glob(path.join(workspace, pattern, 'poetry.lock'))
if match ~= '' then
local venv_base_folder = vim.fn.trim(vim.fn.system('poetry env info -p'))
return path.join(venv_base_folder, 'bin', 'python'), string.format('venv base folder: %s', venv_base_folder)
end
end
-- Fallback to system Python.
return exepath('python3') or exepath('python') or 'python', 'fallback to system python path'
end
M.on_init = function(client)
local python_path, msg = M.pyenv_path(client.config.root_dir)
vim.notify(string.format('%s \ncurrent python path: %s', msg, python_path))
client.config.settings.python.pythonPath = python_path
end
return M

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

@ -1,6 +1,7 @@
local M = {}
local util = require('navigator.util')
local nvim_0_6 = util.nvim_0_6()
local gutil = require('guihua.util')
local lsp = require('vim.lsp')
@ -9,10 +10,9 @@ local log = require('navigator.util').log
local lerr = require('navigator.util').error
local trace = require('navigator.util').trace
local symbol_kind = require('navigator.lspclient.lspkind').symbol_kind
local uv = vim.uv or vim.loop
local cwd = uv.cwd()
local os_name = uv.os_uname().sysname
local is_win = os_name:find('Windows') or os_name:find('MINGW')
local cwd = vim.loop.cwd()
local is_win = vim.loop.os_uname().sysname:find('Windows')
local path_sep = require('navigator.util').path_sep()
local path_cur = require('navigator.util').path_cur()
@ -20,7 +20,7 @@ cwd = gutil.add_pec(cwd)
local ts_nodes = require('navigator.lru').new(1000, 1024 * 1024)
local ts_nodes_time = require('navigator.lru').new(1000)
local TS_analysis_enabled = require('navigator').config_values().treesitter_analysis
local nts = require('navigator.treesitter')
-- extract symbol from range
function M.get_symbol(text, range)
if range == nil then
@ -75,8 +75,7 @@ end
function M.symbols_to_items(result)
local locations = {}
result = result or {}
log(#result)
-- log(result)
for i = 1, #result do
local item = result[i].location
if item ~= nil and item.range ~= nil then
@ -88,9 +87,8 @@ function M.symbols_to_items(result)
if kind ~= nil then
item.text = kind .. ': ' .. item.text
end
if not item.filename then
item.filename = vim.uri_to_fname(item.uri)
end
item.filename = vim.uri_to_fname(item.uri)
item.display_filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
if item.range == nil or item.range.start == nil then
log('range not set', result[i], item)
@ -119,54 +117,59 @@ local function extract_result(results_lsp)
end
end
function M.check_capabilities(feature, bufnr)
local clients = lsp.get_clients({ buffer = bufnr or vim.api.nvim_get_current_buf() })
function M.check_capabilities(feature, client_id)
local clients = lsp.buf_get_clients(client_id or 0)
local supported_client = false
for _, client in pairs(clients) do
-- supported_client = client.resolved_capabilities[feature]
supported_client = client.server_capabilities[feature]
supported_client = client.resolved_capabilities[feature]
if supported_client then
return client
break
end
end
if #clients == 0 then
log('LSP: no client attached')
if supported_client then
return true
else
trace('LSP: server does not support ' .. feature)
if #clients == 0 then
log('LSP: no client attached')
else
trace('LSP: server does not support ' .. feature)
end
return false
end
return false
end
function M.call_sync(method, params, opts, handler)
params = params or {}
opts = opts or {}
log(method, params)
local results_lsp, err = lsp.buf_request_sync(opts.bufnr or 0, method, params, opts.timeout or 1000)
local results_lsp, err = lsp.buf_request_sync(0, method, params, opts.timeout or vim.g.navtator_timeout or 1000)
return handler(err, extract_result(results_lsp), { method = method, no_show = opts.no_show }, nil)
if nvim_0_6() then
handler(err, extract_result(results_lsp), { method = method }, nil)
else
handler(err, method, extract_result(results_lsp), nil, nil)
end
end
function M.call_async(method, params, handler, bufnr)
function M.call_async(method, params, handler)
params = params or {}
local callback = function(...)
util.show(...)
handler(...)
end
bufnr = bufnr or 0
return lsp.buf_request(bufnr, method, params, callback)
return lsp.buf_request(0, method, params, callback)
-- results_lsp, canceller
end
local function ts_functions(uri, optional)
local function ts_functions(uri)
local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then
lerr('ts not enabled')
return nil
end
local ts_func = nts.buf_func
local ts_func = require('navigator.treesitter').buf_func
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -184,9 +187,6 @@ local function ts_functions(uri, optional)
ts_nodes_time:delete(uri)
end
end
if optional then
return
end
local unload = false
if not api.nvim_buf_is_loaded(bufnr) then
trace('! load buf !', uri, bufnr)
@ -206,7 +206,7 @@ local function ts_functions(uri, optional)
return funcs, unload_bufnr
end
local function ts_definition(uri, range, optional)
local function ts_definition(uri, range)
local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then
@ -224,10 +224,7 @@ local function ts_definition(uri, range, optional)
log('ts def from cache')
return tsnodes
end
if optional then
return
end
local ts_def = nts.find_definition
local ts_def = require('navigator.treesitter').find_definition
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -249,7 +246,6 @@ local function ts_definition(uri, range, optional)
end
local function find_ts_func_by_range(funcs, range)
log(funcs, range)
if funcs == nil or range == nil then
return nil
end
@ -265,6 +261,20 @@ local function find_ts_func_by_range(funcs, range)
return result
end
local function order_locations(locations)
table.sort(locations, function(i, j)
if i.uri == j.uri then
if i.range and i.range.start then
return i.range.start.line < j.range.start.line
end
return false
else
return i.uri < j.uri
end
end)
return locations
end
local function slice_locations(locations, max_items)
local cut = -1
if #locations > max_items then
@ -284,98 +294,69 @@ local function slice_locations(locations, max_items)
return first_part, second_part
end
-- local function test_locations()
-- local locations = {
-- { uri = '1', range = { start = { line = 1 } } },
-- { uri = '2', range = { start = { line = 2 } } },
-- { uri = '2', range = { start = { line = 3 } } },
-- { uri = '1', range = { start = { line = 3 } } },
-- { uri = '1', range = { start = { line = 4 } } },
-- { uri = '3', range = { start = { line = 4 } } },
-- { uri = '3', range = { start = { line = 4 } } },
-- }
-- local second_part
-- order_locations(locations)
-- local locations, second_part = slice_locations(locations, 3)
-- log(locations, second_part)
-- 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
local function test_locations()
local locations = {
{ uri = '1', range = { start = { line = 1 } } },
{ uri = '2', range = { start = { line = 2 } } },
{ uri = '2', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } },
}
local second_part
order_locations(locations)
local locations, second_part = slice_locations(locations, 3)
log(locations, second_part)
end
function M.locations_to_items(locations, ctx)
ctx = ctx or {}
local max_items = ctx.max_items or 1000 --
trace(ctx, max_items)
local max_items = ctx.max_items or 100000 --
local client_id = ctx.client_id or 1
local enc = util.encoding(client_id)
if not locations or vim.tbl_isempty(locations) then
vim.notify('list not avalible', vim.log.levels.WARN)
vim.notify('list not avalible', vim.lsp.log_levels.WARN)
return
end
local width = 4 -- text max width
local width = 4
local items = {}
-- items and locations may not matching
local uri_def = {}
order_locations(locations)
local second_part
locations, second_part = slice_locations(locations, max_items)
if second_part and #second_part > 0 then
log('second part', #locations, #second_part)
trace(#locations, locations[1], #second_part, second_part and second_part[1])
end
trace(locations)
vim.cmd([[set eventignore+=FileType]])
local now = uv.now()
local unload_bufnrs = {}
local file_cnt = {}
for i, loc in ipairs(locations) do
local looptimer = uv.now()
local funcs = nil
local item = lsp.util.locations_to_items({ loc }, enc)[1]
-- log(item)
item.range = locations[i].range or locations[i].targetRange
item.uri = locations[i].uri or locations[i].targetUri
item.definition = locations[i].definition
if is_win then
trace(item.uri, cwd) -- file:///C:/path/to/file
log(item.uri) -- file:///C:/path/to/file
log(cwd)
end
file_cnt[item.uri] = (file_cnt[item.uri] or 0) + 1
-- only load top 30 file.items
local proj_file = (item.uri:find(cwd) or is_win) and i < _NgConfigValues.treesitter_analysis_max_num and table.getn(file_cnt) < _NgConfigValues.treesitter_analysis_max_fnum -- getn deprecated, but it is the best solution for getting dict size
-- only load top 30 file.
local proj_file = item.uri:find(cwd) or is_win or i < 30
local unload, def
local context = ''
if not proj_file then
trace('not proj file', i, item.uri)
end
if TS_analysis_enabled and not ctx.no_show and proj_file then
local ts_context = nts.ref_context
local bufnr = vim.uri_to_bufnr(item.uri)
if not api.nvim_buf_is_loaded(bufnr) then
log('! load buf !', item.uri, bufnr)
vim.fn.bufload(bufnr)
unload = bufnr
end
context = ts_context({ bufnr = bufnr, pos = item.range }) or 'not found'
trace('ts ctx', i, context, uv.now() - looptimer)
if TS_analysis_enabled and proj_file then
funcs, unload = ts_functions(item.uri)
-- TODO: unload buffers
if unload then
table.insert(unload_bufnrs, unload)
unload = nil
end
if not uri_def[item.uri] then
-- find def in file
def, unload = ts_definition(item.uri, item.range, ts_optional(i, #unload_bufnrs))
def, unload = ts_definition(item.uri, item.range)
if def and def.start then
uri_def[item.uri] = def
if def.start then -- find for the 1st time
@ -399,7 +380,6 @@ function M.locations_to_items(locations, ctx)
table.insert(unload_bufnrs, unload)
end
end
trace('perf: ts ctx', i, uv.now() - looptimer, uv.now() - now)
trace(uri_def[item.uri], item.range) -- set to log if need to get all in rnge
local def1 = uri_def[item.uri]
if def1 and def1.start and item.range then
@ -411,28 +391,15 @@ function M.locations_to_items(locations, ctx)
end
item.filename = assert(vim.uri_to_fname(item.uri))
local filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
if ctx.no_show then
local shorten = require('guihua.util').shorten
filename = shorten(filename)
end
item.display_filename = filename or item.filename
item.call_by = context -- find_ts_func_by_range(funcs, item.range)
item.rpath = util.get_relative_path(cwd, gutil.add_pec(item.filename))
if is_win then
-- windows C: vs c: -- log(item.filename, filename, cwd .. path_sep, path_cur)
item.display_filename = item.rpath or item.display_filename
end
item.call_by = find_ts_func_by_range(funcs, item.range)
item.rpath = util.get_relative_path(cwd, item.filename)
width = math.max(width, #item.text)
item.symbol_name = M.get_symbol(item.text, item.range)
item.lhs = check_lhs(item.text, item.symbol_name)
table.insert(items, item)
trace('perf: ts render', uv.now() - looptimer, uv.now() - now)
loop_timer = uv.now()
end
trace(uri_def)
@ -449,13 +416,12 @@ function M.locations_to_items(locations, ctx)
vim.cmd([[set eventignore-=FileType]])
trace(items)
return items, width + 30, second_part -- TODO handle long line?
return items, width + 24, second_part -- TODO handle long line?
end
function M.symbol_to_items(locations)
if not locations or vim.tbl_isempty(locations) then
vim.notify('list not avalible', vim.log.levels.WARN)
vim.notify('list not avalible', vim.lsp.log_levels.WARN)
return
end
@ -465,9 +431,6 @@ function M.symbol_to_items(locations)
if i.definition then
return true
end
if j.definition then
return false
end
if i.uri == j.uri then
if i.range and i.range.start then
return i.range.start.line < j.range.start.line
@ -495,7 +458,7 @@ end
function M.request(method, hdlr) -- e.g textDocument/reference
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
util.for_each_buffer_client(bufnr, function(client, _, _)
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
client.request(method, ref_params, hdlr, bufnr)
end)
end

@ -1,115 +1,82 @@
local util = require('navigator.util')
local mk_handler = util.mk_handler
local log = util.log
local lsphelper = require('navigator.lspwrapper')
local gui = require('navigator.gui')
local lsp = require('navigator.lspwrapper')
local trace = require('navigator.util').trace
ListViewCtrl = ListViewCtrl or require('guihua.listviewctrl').ListViewCtrl
-- local partial = util.partial
-- local cwd = vim.loop.cwd()
local uv = vim.uv or vim.loop
-- local lsphelper = require "navigator.lspwrapper"
local locations_to_items = lsphelper.locations_to_items
local function order_locations(locations)
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.range and i.range.start then
return i.range.start.line < j.range.start.line
end
return false
else
return i.uri < j.uri
end
end)
return locations
end
local function warmup_treesitter()
local parsers = require('nvim-treesitter.parsers')
local bufnr = vim.api.nvim_get_current_buf()
local parser = parsers.get_parser(bufnr)
if not parser then
log('err: ts not loaded ' .. vim.o.ft)
return
end
end
local M = {}
local ref_view = function(err, locations, ctx, cfg)
cfg = cfg or {}
local truncate = cfg and cfg.truncate or 20
local opts = {}
trace('ref_view', err, ctx, #locations, cfg, locations)
-- log(#locations, locations[1])
trace('arg1', err, ctx, locations)
trace(locations)
if ctx.combine then
-- wait for both reference and definition LSP request
-- wait for both request
if ctx.results == nil then
return
end
if (ctx.results.definitions == nil) or (ctx.results.references == nil) then
if #ctx.results.definitions.result == nil or ctx.results.references.result == nil then
log('not all requests returned')
return
end
local definitions = ctx.results.definitions
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
vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.log.levels.WARN)
vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.lsp.log_levels.WARN)
end
locations = {}
if definitions and definitions.result then
if definitions.result then
for i, _ in ipairs(definitions.result) do
definitions.result[i].definition = true
end
vim.list_extend(locations, definitions.result)
end
if references and references.result and #references.result > 0 then
local refs = references.result
order_locations(refs)
vim.list_extend(locations, refs)
if references.result then
vim.list_extend(locations, references.result)
end
ctx = references.ctx or definitions.ctx
err = nil
-- lets de-dup first 10 elements. some lsp does not recognize definition and reference difference
locations = util.dedup(locations)
trace(locations)
cfg = references.config or definitions.config
trace(ctx, locations)
end
-- log('num bufnr: ', num, bufnr)
-- log("num", num)
-- log("bfnr", bufnr)
if err ~= nil then
vim.notify(
'lsp ref callback error' .. vim.inspect(err) .. vim.inspect(ctx) .. vim.inspect(locations),
vim.log.levels.WARN
vim.lsp.log_levels.WARN
)
log('ref callback error, lsp may not ready', err, ctx, vim.inspect(locations))
return
end
if type(locations) ~= 'table' then
log(locations)
log('ctx', ctx)
vim.notify('incorrect setup' .. vim.inspect(locations), vim.lsp.log_levels.WARN)
return
end
if locations == nil or vim.tbl_isempty(locations) then
vim.notify('References not found', vim.log.levels.INFO)
vim.notify('References not found', vim.lsp.log_levels.WARN)
return
end
ctx.max_items = truncate
local items, width, second_part = locations_to_items(locations, ctx)
local thread_items = {}
if vim.fn.empty(second_part) == 0 then
thread_items = vim.deepcopy(items)
end
log('splits: ', #locations, #items, #second_part)
local thread_items = vim.deepcopy(items)
log('splits: ', #items, #second_part)
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
local wwidth = vim.api.nvim_get_option('columns')
local mwidth = _NgConfigValues.width
width = math.min(width + 30, math.floor(wwidth * mwidth))
width = math.min(width + 30, 120, math.floor(wwidth * mwidth))
-- log(items)
-- log(width)
opts = {
@ -120,98 +87,67 @@ local ref_view = function(err, locations, ctx, cfg)
width = width,
api = 'Reference',
enable_preview_edit = true,
title = 'References ' .. vim.fn.expand('<cword>'),
}
local listview
if not ctx.no_show then
listview = gui.new_list_view(opts)
if listview == nil then
vim.notify('failed to create preview windows', vim.log.levels.INFO)
return
end
end
local listview = gui.new_list_view(opts)
if ctx.no_show then
opts.side_panel = true
local data = require('navigator.render').prepare_for_render(items, opts)
return data
if listview == nil then
vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO)
return
end
-- trace("update items", listview.ctrl.class)
local nv_ref_async
nv_ref_async = uv.new_async(vim.schedule_wrap(function()
nv_ref_async = vim.loop.new_async(vim.schedule_wrap(function()
log('$$$$$$$$ seperate thread... $$$$$$$$')
if vim.tbl_isempty(second_part) then
return
end
log('$$$$$$$$ --- seperate thread... --- $$$$$$$$')
ctx.max_items = #second_part -- proccess all the rest
local items2 = locations_to_items(second_part, ctx)
vim.list_extend(thread_items, items2)
local data = require('navigator.render').prepare_for_render(thread_items, opts)
log('thread data size', #data)
listview.ctrl:on_data_update(data)
if nv_ref_async then
uv.close(nv_ref_async)
vim.loop.close(nv_ref_async)
else
log('invalid ref_async')
log('invalid asy', nv_ref_async)
end
end))
vim.defer_fn(function()
uv.new_thread(function(asy)
vim.loop.new_thread(function(asy)
asy:send()
end, nv_ref_async)
end, 10)
end, 100)
return listview, items, width
end
local ref_hdlr = function(err, locations, ctx, cfg)
local ref_hdlr = mk_handler(function(err, locations, ctx, cfg)
_NgConfigValues.closer = nil
trace(err, locations, ctx, cfg)
if ctx.no_show then
return ref_view(err, locations, ctx, cfg)
end
M.async_hdlr = uv.new_async(vim.schedule_wrap(function()
M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function()
ref_view(err, locations, ctx, cfg)
if M.async_hdlr:is_active() then
M.async_hdlr:close()
end
end))
M.async_hdlr:send()
end
end)
local async_ref = function()
local ref_params = vim.lsp.util.make_position_params()
local results = {}
local results = { definitions = {}, references = {} }
ref_params.context = { includeDeclaration = false }
lsp.call_async('textDocument/definition', ref_params, function(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 }
log('number of result', #result)
ctx = ctx or {}
ctx.results = results
ctx.combine = true
ref_view(err, result, ctx, config)
end) -- return asyncresult, canceller
ref_params.context = { includeDeclaration = false }
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)
results.references = { error = err, result = result, ctx = ctx, config = config }
ctx = ctx or {}
@ -221,68 +157,17 @@ local async_ref = function()
end) -- return asyncresult, canceller
end
-- Get positions of LSP reference symbols
-- a function from smjonas/inc-rename.nvim
-- https://github.com/smjonas/inc-rename.nvim/blob/main/lua/inc_rename/init.lua
local function fetch_lsp_references(bufnr, params, callback)
if not vim.lsp.get_clients then
vim.lsp.get_clients = vim.lsp.get_clients
end
local clients = vim.lsp.get_clients({
bufnr = bufnr,
})
clients = vim.tbl_filter(function(client)
return client.supports_method('textDocument/rename')
end, clients)
if #clients == 0 then
log('[nav-rename] No active language server with rename capability')
vim.notify('No active language server with reference capability')
end
if not params then
log('[nav-rename] No params provided')
vim.notify('No params provided')
end
params.context = params.context or { includeDeclaration = true }
log(bufnr, params)
-- return id, closer
return vim.lsp.buf_request(
bufnr,
'textDocument/references',
params,
function(err, result, ctx, cfg)
trace(result)
if err then
log('[nav-rename] Error while finding references: ' .. err.message)
return
end
if not result or vim.tbl_isempty(result) then
log('[nav-rename] Nothing to rename', result)
return
end
if callback then
callback(err, result, ctx, cfg)
end
end
)
end
local ref_req = function()
if _NgConfigValues.closer ~= nil then
-- do not call it twice
_NgConfigValues.closer()
end
if _NgConfigValues.treesitter_analysis then
warmup_treesitter()
end
local ref_params = vim.lsp.util.make_position_params()
ref_params.context = { includeDeclaration = true }
-- lsp.call_async("textDocument/references", ref_params, ref_hdlr) -- return asyncresult, canceller
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
log('bufnr', bufnr)
local ids, closer = fetch_lsp_references(bufnr, ref_params, ref_hdlr)
local ids, closer = vim.lsp.buf_request(bufnr, 'textDocument/references', ref_params, ref_hdlr)
log(ids)
_NgConfigValues.closer = closer
@ -293,47 +178,20 @@ local ref = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
util.for_each_buffer_client(bufnr, function(client, _, _)
if client.server_capabilities.referencesProvider then
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, bufnr)
if client.resolved_capabilities.find_references then
client.request('textDocument/references', ref_params, ref_hdlr, bufnr)
end
end)
end
local function side_panel()
local Panel = require('guihua.panel')
local currentWord = vim.fn.expand('<cword>')
local p = Panel:new({
scope = 'range',
header = '' .. currentWord .. ' ref ',
render = function(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then
return
end
local ref_params = vim.lsp.util.make_position_params()
local sync_req = require('navigator.lspwrapper').call_sync
return sync_req(
'textDocument/references',
ref_params,
{ timeout = 1000, bufnr = bufnr, no_show = true },
vim.lsp.with(function(err, locations, ctx, cfg)
cfg.side_panel = true
return ref_hdlr(err, locations, ctx, cfg)
end, { no_show = true })
)
end,
})
p:open(true)
end
return {
side_panel = side_panel,
fetch_lsp_references = fetch_lsp_references,
reference_handler = ref_hdlr,
reference = ref_req,
ref_view = ref_view,
async_ref = async_ref,
all_ref = ref,
}

@ -1,557 +1,16 @@
-- the preview and cache are copy from
-- smjonas/inc-renamer.nvim
-- https://github.com/smjonas/inc-rename.nvim/blob/main/lua/inc_rename/init.lua
-- inplace rename are from neovim vim.lsp.buf.rename
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/rename.lua
local M = {}
local util = require('navigator.util')
local log = util.log
local api = vim.api
local vfn = vim.fn
local M = {
hl_group = 'Substitute',
}
local make_position_params = vim.lsp.util.make_position_params
local rename_group = api.nvim_create_augroup('nav-rename', {})
local state = {
should_fetch_references = true,
cached_lines = nil,
input_win_id = nil,
input_bufnr = nil,
confirm = nil,
oldname = nil,
newname = nil,
err = nil,
}
local backspace = api.nvim_replace_termcodes('<bs>', true, false, true)
local ns = api.nvim_create_namespace('nav-rename')
local function set_error(msg, level)
state.err = { msg = msg, level = level }
state.cached_lines = nil
end
local function ts_symbol()
local ok, _ = pcall(require, 'nvim-treesitter')
if not ok then
vim.notify('treesitter not installed')
-- try best
return {}
end
local bufnr = api.nvim_get_current_buf()
local queries = require('nvim-treesitter.query')
local ft_to_lang = require('nvim-treesitter.parsers').ft_to_lang
local lang = ft_to_lang(vim.bo[bufnr].filetype)
local query = (vim.fn.has('nvim-0.9') == 1) and vim.treesitter.query.get(lang, 'highlights')
or vim.treesitter.get_query(lang, 'highlights')
local ts_utils = require('nvim-treesitter.ts_utils')
local current_node = ts_utils.get_node_at_cursor()
if not current_node then
return
end
local start_row, _, end_row, _ = current_node:range()
for id, _, _ in query:iter_captures(current_node, 0, start_row, end_row) do
local name = query.captures[id]
if name:find('builtin') or name:find('keyword') then
return
end
end
return current_node
end
local function visible(bufnr)
if api.nvim_buf_is_loaded(bufnr) then
for _, win in ipairs(api.nvim_tabpage_list_wins(0)) do
if api.nvim_win_get_buf(win) == bufnr then
return true
end
end
end
return false
end
local function hash(a, b, c)
local cantor = function(x, y)
return (x + y + 1) * (x + y) / 2 + y
end
return cantor(a, cantor(b, c))
end
-- a function from smjonas/inc-rename.nvim
local function cache_lines(result)
local cached_lines = {}
local exists = {}
for _, res in ipairs(result) do
local range = res.range
if range.start.line == range['end'].line then
local bufnr
if res.uri then
bufnr = vim.uri_to_bufnr(res.uri)
else
bufnr = vim.api.nvim_get_current_buf()
end
if visible(bufnr) then
if not cached_lines[bufnr] then
cached_lines[bufnr] = {}
end
if not exists[bufnr] then
exists[bufnr] = {}
end
local line_nr = range.start.line
local line = api.nvim_buf_get_lines(bufnr, line_nr, line_nr + 1, false)[1]
local start_col, end_col = range.start.character, range['end'].character
local line_info = { text = line, start_col = start_col, end_col = end_col }
local h = hash(line_nr, start_col, end_col)
if not exists[bufnr][h] then
if cached_lines[bufnr][line_nr] then
table.insert(cached_lines[bufnr][line_nr], line_info)
else
cached_lines[bufnr][line_nr] = { line_info }
end
exists[bufnr][h] = true
end
-- log(cached_lines[bufnr])
end
end
end
return cached_lines
end
local function fetch_lsp_references(bufnr, lsp_params, callback)
require('navigator.reference').fetch_lsp_references(
bufnr,
lsp_params,
function(err, result, ctx, cfg)
if err then
log('[nav-rename] Error while finding references: ' .. err.message, ctx, cfg)
return
end
if not result or vim.tbl_isempty(result) then
log('[nav-rename] Nothing to rename', result)
return
end
state.total = #result
state.cached_lines = cache_lines(result)
state.should_fetch_references = false
if callback then
callback()
end
end
)
end
-- inspired by smjonas/inc-rename.nvim
local function teardown(switch_buffer)
state.should_fetch_references = true
state.cached_lines = nil
state.oldname = nil
state.newname = nil
if state.input_win_id and api.nvim_win_is_valid(state.input_win_id) then
state.input_win_id = nil
if switch_buffer then
api.nvim_set_current_win(state.win_id)
end
end
end
local function restore_buffer()
for bufnr, line_info_per_bufnr in pairs(state.cached_lines or {}) do
for line_nr, line_info in pairs(line_info_per_bufnr) do
log(line_nr, line_info[1].text)
api.nvim_buf_set_lines(bufnr, line_nr, line_nr + 1, false, { line_info[1].text })
end
end
end
-- Called when the user is still typing the command or the command arguments
-- inspired by smjonas/inc-rename.nvim
local function incremental_rename_preview(opts, preview_ns, preview_buf)
log(opts, preview_ns, preview_buf)
local new_name = opts.args
state.new_name = new_name
vim.v.errmsg = ''
if state.should_fetch_references then
fetch_lsp_references(preview_buf, state.lsp_params, function()
incremental_rename_preview(opts, preview_ns, preview_buf)
end)
end
if not state.cached_lines then
log('lsp references not fetched yet')
return
end
local function apply_highlights_fn(bufnr, line_nr, line_info)
local offset = 0
local updated_line = line_info[1].text
local highlight_positions = {}
for _, info in ipairs(line_info) do
updated_line = updated_line:sub(1, info.start_col + offset)
.. new_name
.. updated_line:sub(info.end_col + 1 + offset)
table.insert(highlight_positions, {
start_col = info.start_col + offset,
end_col = info.start_col + #new_name + offset,
})
-- Offset by the length difference between the new and old names
offset = offset + #new_name - (info.end_col - info.start_col)
end
api.nvim_buf_set_lines(bufnr or opts.bufnr, line_nr, line_nr + 1, false, { updated_line })
for _, hl_pos in ipairs(highlight_positions) do
api.nvim_buf_add_highlight(
bufnr or opts.bufnr,
preview_ns,
M.hl_group,
line_nr,
hl_pos.start_col,
hl_pos.end_col
)
end
end
for bufnr, line_info_per_bufnr in pairs(state.cached_lines) do
for line_nr, line_info in pairs(line_info_per_bufnr) do
apply_highlights_fn(bufnr, line_nr, line_info)
end
end
state.preview_ns = preview_ns
end
-- function rewrite from smjonas/inc-rename.nvim
local function perform_lsp_rename(new_name, params)
params = params or make_position_params()
params.newName = new_name
vim.lsp.buf_request(0, 'textDocument/rename', params, function(err, result, ctx, _)
if err and err.message then
vim.notify('[nav-rename] Error while renaming: ' .. err.message, vim.log.levels.ERROR)
return
end
if not result or vim.tbl_isempty(result) then
set_error('[nav-rename] Nothing renamed', vim.log.levels.INFO)
return
end
local client = vim.lsp.get_client_by_id(ctx.client_id)
vim.lsp.util.apply_workspace_edit(result, client.offset_encoding)
if _NgConfigValues.lsp.rename.show_result then
local changed_instances = 0
local changed_files = 0
local with_edits = result.documentChanges ~= nil
for _, change in pairs(result.documentChanges or result.changes) do
changed_instances = changed_instances + (with_edits and #change.edits or #change)
changed_files = changed_files + 1
end
local message = string.format(
'Renamed %s instance%s %s in %s file%s \n to %s:',
changed_instances,
changed_instances == 1 and '' or 's',
state.oldname,
changed_files,
changed_files == 1 and '' or 's',
new_name
)
vim.notify(message)
end
if M.config and M.config.post_hook then
M.config.post_hook(result)
end
end)
end
local function inc_rename_execute(opts)
if vim.v.errmsg ~= '' then
log(
'[nav-rename] An error occurred in the preview function.' .. vim.v.errmsg,
vim.log.levels.ERROR
)
elseif state.err then
log(state.err.msg, state.err.level)
end
restore_buffer()
teardown(true)
perform_lsp_rename(opts.args, opts.params)
end
-- local rename_prompt = 'Rename -> '
M.rename = function()
if _NgConfigValues.lsp.rename.style == 'floating-preview' then
return M.rename_preview()
end
if _NgConfigValues.lsp.rename.style == 'inplace-preview' then
return M.rename_inplace()
end
local input = vim.ui.input
local ghinput = require('guihua.input')
-- make sure everything was restored
ghinput.setup({
on_change = function(new_name) end,
on_concel = function(new_name) end,
title = 'lsp rename',
on_cancel = function() end,
})
vim.ui.input = ghinput.input
vim.ui.input = require('guihua.floating').input
vim.lsp.buf.rename()
vim.defer_fn(function()
vim.ui.input = input
end, 1000)
end
M.rename_preview = function()
local input = vim.ui.input
state.cached_lines = {}
state.confrim = nil
state.should_fetch_references = true
state.lsp_params = make_position_params()
if not ts_symbol() then
return
end
rename_group = api.nvim_create_augroup('nav-rename', {})
if vim.fn.has('nvim-0.8.0') ~= 1 then
vim.ui.input = require('guihua.floating').input
vim.lsp.buf.rename()
return vim.defer_fn(function()
vim.ui.input = input
end, 1000)
end
local ghinput = require('guihua.input')
state.win_id = vim.fn.win_getid(0)
state.lsp_params = make_position_params()
state.preview_buf = vim.api.nvim_get_current_buf()
local inputopts = {
on_change = function(new_name)
incremental_rename_preview({ args = new_name }, ns, state.preview_buf)
end,
preview_buf = state.preview_buf,
on_confirm = function(new_name)
-- put back everything
log('on_confirm', new_name)
restore_buffer()
end,
on_cancel = function(new_name)
restore_buffer()
teardown(true)
log('cancel', new_name)
end,
}
if vim.fn.has('nvim-0.9.0') == 1 then
inputopts.title = 'symbol rename'
end
ghinput.setup(inputopts)
vim.ui.input = ghinput.input
vim.lsp.buf.rename()
end
-- rename without floating window
-- a moodify version of neovim vim.lsp.buf.rename
function M.rename_inplace(new_name, options)
options = options or {}
state.confrim = nil
state.should_fetch_references = true
state.cached_lines = {}
state.lsp_params = make_position_params()
rename_group = api.nvim_create_augroup('nav-rename', {})
local bufnr = options.bufnr or api.nvim_get_current_buf()
local clients = vim.lsp.get_clients({
bufnr = bufnr,
name = options.name,
})
if options.filter then
clients = vim.tbl_filter(options.filter, clients)
end
if not ts_symbol() then
return
end
-- Clients must at least support rename, prepareRename is optional
clients = vim.tbl_filter(function(client)
return client.supports_method('textDocument/rename')
end, clients)
if #clients == 0 then
vim.notify('[LSP] Rename, no matching language servers with rename capability.')
end
local confirm_key = _NgConfigValues.lsp.rename.confirm
local cancel_key = _NgConfigValues.lsp.rename.concel
local win = api.nvim_get_current_win()
-- Compute early to account for cursor movements after going async
local cword = vim.fn.expand('<cword>')
state.oldname = cword
---@private
local function get_text_at_range(range, offset_encoding)
return api.nvim_buf_get_text(
bufnr,
range.start.line,
util._get_line_byte_from_position(bufnr, range.start, offset_encoding),
range['end'].line,
util._get_line_byte_from_position(bufnr, range['end'], offset_encoding),
{}
)[1]
end
local on_finish_cb = function()
log('leave insert')
api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
api.nvim_del_augroup_by_name('nav-rename')
vim.keymap.del({ 'i', 'n' }, confirm_key, { buffer = bufnr })
vim.keymap.del({ 'i', 'n' }, cancel_key, { buffer = bufnr })
restore_buffer()
if state.confirm then
-- lets put back
log('execute rename')
inc_rename_execute({ args = state.new_name or vim.fn.expand('<cword>'), params = {} })
end
end
local try_use_client
try_use_client = function(idx, client)
if not client then
return
end
local params = make_position_params(win, client.offset_encoding)
---@private
local function rename(name)
params.newName = name
local handler = client.handlers['textDocument/rename']
or vim.lsp.handlers['textDocument/rename']
client.request('textDocument/rename', params, function(...)
handler(...)
try_use_client(next(clients, idx))
end, bufnr)
end
if client.supports_method('textDocument/prepareRename') then
-- log(params)
client.request('textDocument/prepareRename', params, function(err, result)
if err or result == nil then
if next(clients, idx) then
try_use_client(next(clients, idx))
else
local msg = err and ('Error on prepareRename: ' .. (err.message or ''))
or 'Nothing to rename'
vim.notify(msg, vim.log.levels.INFO)
end
return
end
incremental_rename_preview({ args = cword, floating = false }, 0, bufnr)
if new_name then
return rename(new_name)
end
vim.api.nvim_create_autocmd({ 'TextChangedI', 'TextChanged' }, {
group = rename_group,
callback = function()
local w = vim.fn.expand('<cword>')
local curl = vfn.getline('.')
local curc = curl:sub(vfn.col('.'), vfn.col('.'))
local node = ts_symbol()
if node and node:type():find('identifier') then
w = vim.treesitter.get_node_text(node, bufnr)
log(node:range(), node:type())
else
-- log(curc, node:type(), vim.treesitter.get_node_text(node, bufnr))
-- cursor at end of symbol
if curc:match('%W') and curc ~= '_' then
local cur_pos = vim.fn.getpos('.')
cur_pos[3] = cur_pos[3] - 1
vfn.setpos('.', cur_pos)
log('move back')
node = ts_symbol()
if node and node:type():find('identifier') then
w = vim.treesitter.get_node_text(node, bufnr)
else
w = vim.fn.expand('<cword>')
end
cur_pos[3] = cur_pos[3] + 1
vfn.setpos('.', cur_pos)
end
end
log(curc, w)
incremental_rename_preview({ args = w, floating = false }, ns, bufnr)
end,
})
vim.keymap.set({ 'i', 'n' }, confirm_key, function()
print('done rename')
local input = vim.fn.expand('<cword>')
log('newname', input)
state.confirm = true
vim.cmd('stopinsert')
on_finish_cb()
end, { buffer = bufnr })
if cancel_key == nil or cancel_key == '' then
vim.api.nvim_create_autocmd({ 'InsertLeave' }, {
group = rename_group,
callback = function()
state.confirm = nil
on_finish_cb()
end,
})
else
vim.keymap.set({ 'i', 'n' }, cancel_key, function()
print('cancel rename')
state.confirm = nil
on_finish_cb()
end, { buffer = bufnr })
end
vim.cmd('noautocmd startinsert')
end, bufnr)
else
assert(
client.supports_method('textDocument/rename'),
'Client must support textDocument/rename'
)
if new_name then
rename(new_name)
return
end
local prompt_opts = {
prompt = 'New Name: ',
default = cword,
}
vim.ui.input(prompt_opts, function(input)
if not input or #input == 0 then
return
end
rename(input)
end)
end
end
try_use_client(next(clients))
end
return M

@ -1,18 +1,16 @@
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local clone = require('guihua.util').clone
local log = require"guihua.log".info
local trace = require"guihua.log".trace
local M = {}
local clone = require'guihua.util'.clone
local function filename(url)
if url == nil then
return ''
end
return url:match('^.+/(.+)$') or url
return url:match("^.+/(.+)$") or url
end
local function extension(url)
local ext = url:match('^.+(%..+)$') or 'txt'
local ext = url:match("^.+(%..+)$") or "txt"
return string.sub(ext, 2)
end
@ -40,6 +38,7 @@ local function get_pads(win_width, text, postfix)
i = i + rem * 10
-- log(i)
end
end
if i > 3 then
@ -53,32 +52,40 @@ end
function M.prepare_for_render(items, opts)
opts = opts or {}
if items == nil or #items < 1 then
vim.notify('no item found or empty fields', vim.log.levels.INFO)
vim.notify("no item found or empty fields", vim.lsp.log_levels.INFO)
return
end
local item = clone(items[1])
local display_items = { item }
local display_items = {item}
local last_summary_idx = 1
local total_ref_in_file = 1
local total = opts.total
local icon = ''
local lspapi = opts.api or ''
local icon = ""
local lspapi = opts.api or ""
local ok, devicons = pcall(require, 'nvim-web-devicons')
local ok, devicons = pcall(require, "nvim-web-devicons")
if ok then
local fn = filename(items[1].filename)
local ext = extension(fn)
icon = devicons.get_icon(fn, ext) or icon
end
-- local call_by_presented = false
opts.width = opts.width or math.floor(vim.api.nvim_get_option('columns') * 0.8)
local call_by_presented = false
local width = 100
opts.width = opts.width or width
local win_width = opts.width -- buf
for i = 1, #items do
if items[i].call_by and #items[i].call_by > 0 then
call_by_presented = true
end
end
-- log(items[1])
for i = 1, #items do
local space
local trim
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 dfn = items[i].display_filename
@ -91,23 +98,18 @@ function M.prepare_for_render(items, opts)
display_items[last_summary_idx].filename_only = true
-- trace(items[i], items[i].filename, last_summary_idx, display_items[last_summary_idx].filename)
-- TODO refact display_filename generate part
if items[i].filename == fn or opts.hide_filename then
if items[i].filename == fn then
space, trim = get_pads(opts.width, icon .. ' ' .. dfn, lspapi_display .. ' 14 of 33 ')
if trim and opts.width > 50 and #dfn > opts.width - 20 then
local fn1 = string.sub(dfn, 1, opts.width - 50)
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 = ' '
-- log("trim", fn1, fn2)
end
local api_disp = string.format(
'%s %s%s%s %i',
icon,
display_items[last_summary_idx].display_filename,
space,
lspapi_display,
total_ref_in_file
)
local api_disp = string.format("%s %s%s%s %i", icon,
display_items[last_summary_idx].display_filename, space,
lspapi_display, total_ref_in_file)
if total then
api_disp = api_disp .. ' of: ' .. tostring(total)
@ -116,18 +118,20 @@ function M.prepare_for_render(items, opts)
display_items[last_summary_idx].text = api_disp
total_ref_in_file = total_ref_in_file + 1
else
lspapi_display = lspapi
item = clone(items[i])
space, trim =
get_pads(opts.width, icon .. ' ' .. item.display_filename, lspapi_display .. ' 12 of 34')
space, trim = get_pads(opts.width, icon .. ' ' .. item.display_filename,
lspapi_display .. ' 12 of 33')
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)
.. '󰇘'
.. string.sub(item.display_filename, #item.display_filename - 10, #item.display_filename)
item.display_filename = string.sub(item.display_filename, 1, opts.width - 52) .. ""
.. string.sub(item.display_filename,
#item.display_filename - 10,
#item.display_filename)
space = ' '
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)
table.insert(display_items, item)
@ -136,56 +140,58 @@ function M.prepare_for_render(items, opts)
end
-- content of code lines
item = clone(items[i])
if opts.side_panel then
item.text = item.text:gsub('%s+', ' ')
else
item.text = require('navigator.util').trim_and_pad(item.text)
end
item.text = string.format('%4i: %s', item.lnum, item.text)
local ts_report = ''
item.text = require'navigator.util'.trim_and_pad(item.text)
item.text = string.format("%4i: %s", item.lnum, item.text)
local ts_report = ""
if item.lhs then
ts_report = _NgConfigValues.icons.value_changed
end
-- log(item.text, item.symbol_name, item.uri)
-- log(item.text)
if item.definition then
log('definition', item.call_by, item.symbol_name, item.text)
if opts.side_panel then
ts_report = _NgConfigValues.icons.value_definition
else
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end
local header_len = #ts_report + 4 -- magic number 2
trace(ts_report, header_len)
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
if item.call_by ~= nil and item.call_by ~= '' then
ts_report = ts_report .. _NgConfigValues.icons.match_kinds['function'] .. item.call_by
if item.call_by ~= nil and #item.call_by > 0 then
trace("call_by:", #item.call_by)
for _, value in pairs(item.call_by) do
if value.node_text then
local txt = value.node_text:gsub('%s*[%[%(%{]*%s*$', '')
local endwise = '{}'
if value.type == 'method' or value.type == 'function' then
endwise = '()'
local syb = items[i].symbol_name
if txt == items[i].symbol_name or (#txt > #syb and txt:sub(#txt - #syb + 1) == syb) then
if ts_report ~= _NgConfigValues.icons.value_definition .. ' ' then
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end
header_len = #ts_report + 1
else
ts_report = ts_report .. ''
end
end
if #ts_report > header_len then
ts_report = ts_report .. ''
end
ts_report = ts_report .. value.kind .. txt .. endwise
trace(item)
end
end
end
if #ts_report > 1 then
space, trim = get_pads(win_width, item.text, ts_report)
local l = math.max(20, opts.width - math.min(20, #ts_report))
if trim and #item.text < l then
trim = false
end
if trim then
item.text = string.sub(item.text, 1, l)
item.text = util.sub_match(item.text)
-- let check if there are unmatched "/'
item.text = string.sub(item.text, 1, opts.width - 20) .. ""
end
if #space + #item.text + #ts_report >= win_width then
if #item.text + #ts_report >= win_width then
space = ' '
local len = math.max(win_width - #item.text - 4, 16)
trace('exceeding', #item.text, #ts_report, win_width, len)
ts_report = ts_report:sub(1, len)
if #item.text + #ts_report > win_width then
trace("exceeding", #item.text, #ts_report, win_width)
space = ' '
else
local remain = win_width - #item.text - #ts_report
trace('remain', remain)
trace("remain", remain)
space = string.rep(' ', remain)
end
end

@ -1,110 +0,0 @@
local diagnostic = vim.diagnostic or vim.lsp.diagnostic
local util = require('navigator.util')
local log = util.log
local api = vim.api
local M = {}
function M.treesitter_and_diag_panel()
local Panel = require('guihua.panel')
local diag = require('navigator.diagnostics')
local ft = vim.bo.filetype
local results = diag.diagnostic_list[ft]
log(diag.diagnostic_list, ft)
local bufnr = api.nvim_get_current_buf()
local p = Panel:new({
header = 'treesitter',
render = function(b)
log('render for ', bufnr, b)
return require('navigator.treesitter').all_ts_nodes(b)
end,
})
p:add_section({
header = 'diagnostic',
render = function(buf)
log(buf, diagnostic)
if diag.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.lsp_and_diag_panel()
local Panel = require('guihua.panel')
local ft = vim.bo.filetype
local diag = require('navigator.diagnostics')
local results = diag.diagnostic_list[ft]
log(diag.diagnostic_list, ft)
local bf = api.nvim_get_current_buf()
ft = vim.api.nvim_buf_get_option(bf, 'buftype') or vim.bo.filetype
if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then
return
end
local lsp
local p = Panel:new({
header = 'symbols',
render = function(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
local params = vim.lsp.util.make_range_params()
local lsp_call = require('navigator.lspwrapper').call_sync
if not Panel:is_open() or vim.fn.empty(lsp) == 1 then
lsp = lsp_call(
'textDocument/documentSymbol',
params,
{ timeout = 2000, bufnr = bufnr, no_show = true },
vim.lsp.with(require('navigator.symbols').document_symbol_handler, { no_show = true })
)
else
lsp_call = require('navigator.lspwrapper').call_async
local f = function(err, result, ctx)
-- log(result, ctx)
ctx = ctx or {}
ctx.no_show = true
lsp = require('navigator.symbols').document_symbol_handler(err, result, ctx)
return lsp
end
lsp_call('textDocument/documentSymbol', params, f, bufnr)
end
return lsp
end,
})
p:add_section({
header = 'diagnostic',
render = function(buf)
log(buf, diagnostic)
if results ~= 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
return M

@ -0,0 +1,75 @@
local gui = require "navigator.gui"
local util = require "navigator.util"
local mk_handler = util.mk_handler
local log = util.log
local partial = util.partial
local lsphelper = require "navigator.lspwrapper"
local cwd = vim.loop.cwd()
local M = {}
--- navigator signature
local match_parameter = function(result)
local signatures = result.signatures
if #signatures < 1 then
return result
end
local signature = signatures[1]
local activeParameter = result.activeParameter or signature.activeParameter
if activeParameter == nil then
return result
end
if signature.parameters == nil then
return
end
if #signature.parameters < 2 or activeParameter + 1 > #signature.parameters then
return result
end
local nextParameter = signature.parameters[activeParameter + 1]
local label = signature.label
if type(nextParameter.label) == "table" then -- label = {2, 4} c style
local range = nextParameter.label
label = label:sub(1, range[1]) .. [[`]] .. label:sub(range[1] + 1, range[2]) .. [[`]]
.. label:sub(range[2] + 1, #label + 1)
signature.label = label
else
if type(nextParameter.label) == "string" then -- label = 'par1 int'
local i, j = label:find(nextParameter.label, 1, true)
if i ~= nil then
label = label:sub(1, i - 1) .. [[`]] .. label:sub(i, j) .. [[`]] .. label:sub(j + 1, #label + 1)
signature.label = label
end
end
end
end
local signature_handler = mk_handler(function(err, result, ctx, config)
if config == nil then
log("config nil")
end
if err then
vim.notify("signature help error: ".. vim.inspect(err) .. vim.inspect(result), ctx, config, vim.lsp.log_levels.WARN)
end
config = config or {}
if config.border == nil then
config.border = _NgConfigValues.border
end
if not (result and result.signatures and result.signatures[1]) then
return
end
match_parameter(result)
local lines = vim.lsp.util.convert_signature_help_to_markdown_lines(result)
if vim.tbl_isempty(lines) then
return
end
local syntax = vim.lsp.util.try_trim_markdown_code_blocks(lines)
config.focus_id = ctx.bufnr .. "lsp_signature"
vim.lsp.util.open_floating_preview(lines, syntax, config)
end)
return {signature_handler = signature_handler}

@ -1,9 +1,11 @@
local gui = require('navigator.gui')
local M = {}
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local log = require('navigator.util').log
local trace = require('navigator.util').trace
local mk_handler = require('navigator.util').mk_handler
local lsphelper = require('navigator.lspwrapper')
local locations_to_items = lsphelper.locations_to_items
local clone = require('guihua.util').clone
local symbol_kind = require('navigator.lspclient.lspkind').symbol_kind
local symbols_to_items = lsphelper.symbols_to_items
@ -11,8 +13,8 @@ function M.workspace_symbols(query)
query = query or pcall(vim.fn.input, 'Query: ')
local bufnr = vim.api.nvim_get_current_buf()
local params = { query = query }
util.for_each_buffer_client(bufnr, function(client, _, _bufnr)
if client.server_capabilities.workspaceSymbolProvider then
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
if client.resolved_capabilities.workspace_symbol then
client.request('workspace/symbol', params, M.workspace_symbol_handler, _bufnr)
end
end)
@ -24,29 +26,24 @@ function M.document_symbols(opts)
loc = 'top_center',
prompt = true,
-- rawdata = true,
api = '󰌱 ',
api = ' ',
}
local bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
local bufnr = vim.api.nvim_get_current_buf()
vim.list_extend(lspopts, opts)
local params = vim.lsp.util.make_position_params()
params.context = { includeDeclaration = true }
params.query = opts.prompt or ''
util.for_each_buffer_client(bufnr, function(client, _, _bufnr)
if client.name ~= 'null-ls' and client.server_capabilities.documentSymbolProvider then
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
if client.resolved_capabilities.document_symbol then
client.request('textDocument/documentSymbol', params, M.document_symbol_handler, _bufnr)
end
end)
end
M.document_symbol_handler = function(err, result, ctx)
M.document_symbol_handler = mk_handler(function(err, result, ctx)
if err then
if error ~= 'timeout' then
vim.notify('failed to get document symbol' .. vim.inspect(ctx) .. err, vim.log.levels.WARN)
else
log('request timeout')
end
return
vim.notify('failed to get document symbol' .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
end
local bufnr = ctx.bufnr or 0
local query = ' '
@ -55,7 +52,7 @@ M.document_symbol_handler = function(err, result, ctx)
end
if not result or vim.tbl_isempty(result) then
vim.notify('symbol ' .. query .. ' not found for buf ' .. vim.inspect(ctx), vim.log.levels.WARN)
vim.notify('symbol' .. query .. 'not found for buf' .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
return
end
local locations = {}
@ -69,9 +66,6 @@ M.document_symbol_handler = function(err, result, ctx)
local kind = symbol_kind(item.kind)
item.name = result[i].name
item.range = result[i].range or result[i].location.range
if item.range == nil then
log('range missing in result', result[i])
end
item.uri = uri
item.selectionRange = result[i].selectionRange
item.detail = result[i].detail or ''
@ -79,65 +73,38 @@ M.document_symbol_handler = function(err, result, ctx)
item.detail = 'func'
end
item.lnum = item.range.start.line + 1
item.lnum = result[i].range.start.line + 1
item.text = '[' .. kind .. ']' .. item.name .. ' ' .. item.detail
item.filename = fname
item.indent_level = 1
item.type = kind
item.node_text = item.name
table.insert(locations, item)
-- local tab = ' ' .. _NgConfigValues.icons.side_panel.tab .. ' '
local function add_children(children, level)
for _, c in pairs(children) do
if result[i].children ~= nil then
for _, c in pairs(result[i].children) do
local child = {}
child.kind = c.kind
child.name = c.name
child.range = c.range or c.location.range
child.range = c.range
local ckind = symbol_kind(child.kind)
child.node_text = child.name
child.type = ckind
child.selectionRange = c.selectionRange
child.filename = fname
child.uri = uri
child.lnum = child.range.start.line + 1
child.lnum = c.range.start.line + 1
child.detail = c.detail or ''
child.indent_level = item.indent_level + level
child.text = string.rep(' ', level) .. ckind .. '' .. child.name .. ' ' .. child.detail
child.text = '' .. ckind .. '' .. child.name .. ' ' .. child.detail
table.insert(locations, child)
if c.children ~= nil then
add_children(c.children, level + 1)
end
end
end
if result[i].children ~= nil then
add_children(result[i].children, 1)
end
end
if ctx.no_show then
return locations
end
local ft = vim.api.nvim_buf_get_option(bufnr, 'ft')
gui.new_list_view({
items = locations,
prompt = true,
rawdata = true,
height = 0.62,
preview_height = 0.1,
title = 'Document Symbols',
ft = ft,
api = _NgConfigValues.icons.doc_symbol,
})
end
gui.new_list_view({ items = locations, prompt = true, rawdata = true, ft = ft, api = '' })
end)
M.workspace_symbol_handler = function(err, result, ctx, cfg)
M.workspace_symbol_handler = mk_handler(function(err, result, ctx, cfg)
trace(err, result, ctx, cfg)
if err then
vim.notify('failed to get workspace symbol' .. vim.inspect(ctx), vim.log.levels.WARN)
vim.notify('failed to get workspace symbol' .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
end
local query = ' '
if ctx.params and ctx.params.query then
@ -145,10 +112,7 @@ M.workspace_symbol_handler = function(err, result, ctx, cfg)
end
if not result or vim.tbl_isempty(result) then
log('symbol not found', ctx)
vim.notify(
'symbol' .. query .. 'not found for buf ' .. tostring(ctx.bufnr),
vim.log.levels.WARN
)
vim.notify('symbol' .. query .. 'not found for buf ' .. tostring(ctx.bufnr), vim.lsp.log_levels.WARN)
return
end
log(result[1])
@ -156,60 +120,7 @@ M.workspace_symbol_handler = function(err, result, ctx, cfg)
log(items[1])
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
gui.new_list_view({
items = items,
prompt = true,
ft = ft,
rowdata = true,
api = '',
title = 'Workspace Symbols',
})
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)
-- redraw the pannel if current buffer modified and saved
local group = vim.api.nvim_create_augroup('guihua_side_panel', { clear = false })
vim.api.nvim_create_autocmd({
'BufWritePost',
}, {
callback = function()
p:redraw(buf)
end,
group = group,
buffer = buf,
desc = 'redraw side panel',
})
vim.api.nvim_create_autocmd({
'BufWinLeave',
}, {
callback = function()
p:close()
end,
group = group,
buffer = buf,
desc = 'close side panel',
})
end
gui.new_list_view({ items = items, prompt = true, ft = ft, rowdata = true, api = '' })
end)
return M

@ -1,32 +1,28 @@
--- Note: some of the functions/code coped from treesitter/refactor/navigation.lua and may be modified
-- to fit in navigator.lua
local gui = require('navigator.gui')
local gui = require "navigator.gui"
local fn = vim.fn
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
error('treesitter not installed')
error("treesitter not installed")
return nil
end
local parsers = require('nvim-treesitter.parsers')
local locals = require('nvim-treesitter.locals')
local ts_utils = require('nvim-treesitter.ts_utils')
local is_in_node_range = vim.treesitter.is_in_node_range
if not is_in_node_range then
is_in_node_range = ts_utils.is_in_node_range
end
local parsers = require "nvim-treesitter.parsers"
local utils = require "nvim-treesitter.utils"
local locals = require 'nvim-treesitter.locals'
local ts_utils = require 'nvim-treesitter.ts_utils'
local api = vim.api
local util = require('navigator.util')
local util = require "navigator.util"
local M = {}
local uv = vim.uv or vim.loop
local cwd = uv.cwd()
local log = util.log
local lerr = util.error
local trace = util.trace
local cwd = vim.loop.cwd()
local log = require"navigator.util".log
local lerr = require"navigator.util".error
local trace = require"navigator.util".trace
local get_icon = function(kind)
if kind == nil or _NgConfigValues.icons.match_kinds[kind] == nil then
@ -47,7 +43,7 @@ function M.goto_definition(bufnr)
local definition = locals.find_definition(node_at_point, bufnr)
if definition ~= node_at_point then
log('def found:', definition:range())
log("def found:", definition:range())
ts_utils.goto_node(definition)
end
end
@ -57,7 +53,7 @@ local function node_is_definination(node)
return false
end
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
return true
@ -73,251 +69,58 @@ local function node_is_definination(node)
end
return false
end
-- use lsp range to find def
function M.find_definition(range, bufnr)
if not range or not range.start then
lerr('find_def incorrect range'..vim.inspect(range))
lerr("find_def incorrect range", range)
return
end
bufnr = bufnr or api.nvim_get_current_buf()
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)
if not root then
return
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
return log('Err: no node at cursor', range)
lerr("no node at cursor")
return
end
local definition = locals.find_definition(node_at_point, bufnr)
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
-- def or not
trace('info: def found:', definition:range(), definition:type())
trace("info: def found:", definition:range(), definition:type())
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
trace('declaraction here ', definition:type())
trace("declaraction here ", definition:type())
local r, c = definition:range()
return { start = { line = r, character = c } }
else
if definition then
-- stylua: ignore start
trace( 'error: def not found in ', bufnr, definition:range(), definition:type())
if definition:parent() then
trace("def not found", definition:parent():type())
end
-- stylua: ignore end
end
end
end
function M.get_tsnode_at_pos(pos, bufnr, ignore_injected_langs)
if not pos or not pos.start then
return
end
local cursor_range = { pos.start.line, pos.start.character }
local root_lang_tree = parsers.get_parser(bufnr)
if not root_lang_tree then
log('Err: ts not loaded ' .. vim.o.ft, bufnr)
return
end
local root
if ignore_injected_langs then
for _, tree in ipairs(root_lang_tree:trees()) do
local tree_root = tree:root()
if tree_root and is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then
root = tree_root
break
end
end
return {start = {line = r, character = c}}
else
root = ts_utils.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree)
trace("error: def not found in ", bufnr, definition:range(), definition:type(), definition:parent():type())
end
if not root then
return
end
return root:named_descendant_for_range(
cursor_range[1],
cursor_range[2],
cursor_range[1],
cursor_range[2]
)
end
-- Trim spaces and opening brackets from end
local transform_line = function(line)
line = line:gsub('%s*[%[%(%{]*%s*$', '')
line = line:gsub('function', '')
line = line:gsub('func%w*%s+', '')
if _NgConfigValues.treesitter_analysis_condense then
line = line:gsub('%([%a%.,%s%[%]%*]+%)', '()')
-- this is for multi return
line = line:gsub('%([%a%.,%s%[%]%*]+%)', '()')
line = line:gsub('%(%)%s*%(%)', '()')
end
return line
end
function M.ref_context(opts)
local options = opts or {}
local bufnr = options.bufnr or api.nvim_get_current_buf()
local parser = parsers.get_parser(bufnr)
if not parser then
log('err: ts not loaded ' .. vim.o.ft)
return
end
local pos = options.pos
if not pos then
pos = { start = vim.lsp.util.make_position_params().position }
end
local indicator_size = options.indicator_size or 100
local type_patterns = options.type_patterns or { 'class', 'function', 'method' }
local transform_fn = options.transform_fn or transform_line
local separator = options.separator or _NgConfigValues.icons.context_separator
local current_node = M.get_tsnode_at_pos(pos, bufnr)
if not current_node then
log('no node at pos', bufnr, pos)
return ''
end
local lines = {}
local expr = current_node
while expr do
local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr)
trace('line', line)
if line ~= '' and not vim.tbl_contains(lines, line) then
table.insert(lines, 1, line)
end
expr = expr:parent()
if #line > _NgConfigValues.treesitter_analysis_depth then
break
end
end
if #lines == 0 then
log('no lines found')
return ''
end
local text = table.concat(lines, separator)
local text_len = #text
if text_len > indicator_size then
local str = text:sub(1, text_len) -- copy string
return util.sub_match(str)
end
return text
end
--- Get definitions of bufnr (unique and sorted by order of appearance).
--- This function copy from treesitter/refactor/navigation.lua
local function get_definitions(bufnr)
local local_nodes = ts_locals.get_locals(bufnr)
-- Make sure the nodes are unique.
local nodes_set = {}
for _, nodes in ipairs(local_nodes) do
local loc = nodes["local"]
trace(loc)
for _, loc in ipairs(local_nodes) do
if loc.definition then
ts_locals.recurse_local_nodes(loc.definition, function(_, node, _, match)
-- lua doesn't compare tables by value,
-- use the value from byte count instead.
local row, col, offset = node:start()
local erow, ecol, end_ = node:end_()
trace(node, match)
trace(row, col, erow, offset, node:parent(), node:parent():start(), node:parent():type())
if
node
and node:parent()
and string.find(node:parent():type(), 'parameter_declaration')
then
log('parameter_declaration skip')
return
end
nodes_set[offset] = { node = node, type = match or '' }
end)
end
if loc.method then -- for go
ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match)
local row, col, start = node:start()
-- stylua: ignore start
trace(row, col, start, def, node, full_match, match,
node:parent(), node:parent():start(), node:parent():type())
-- stylua: ignore end
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()
-- stylua: ignore start
trace( k, l, start, def, node, full_match,
match, node:parent(), node:parent():start(), node:parent():type())
-- stylua: ignore end
if nodes_set[start] == nil then
nodes_set[start] = { node = node, type = match or '' }
end
end)
end
if loc.reference then -- for go
ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match)
local row, col, start = node:start()
local p1, p1t = '', ''
local p2, p2t = '', ''
local p3, p3t = '', ''
if node:parent() and node:parent():parent() then
p1 = node:parent()
p1t = node:parent():type()
p2 = node:parent():parent()
p2t = node:parent():parent():type()
end
if p2 and p2:parent() then
p3 = p2:parent()
p3t = p2:parent():type()
end
-- stylua: ignore start
trace( row, col, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t, p3, p3t)
-- stylua: ignore end
if p1t == 'arrow_function' then
row, col, start = p1:start()
trace('arrow_function 1', row, col)
nodes_set[start] = { node = p1, type = p1t }
end
if p2t == 'arrow_function' then
row, col, start = p2:start()
trace('arrow_function 2', row, col)
nodes_set[start] = { node = p2, type = p2t }
end
if nodes_set[start] == nil then
if -- qualified_type : e.g. io.Reader inside interface
node:parent()
and node:parent():parent()
and node:type() == 'type_identifier'
and node:parent():type() == 'qualified_type'
and string.find(node:parent():parent():type(), 'interface')
then
trace('add node', node)
nodes_set[start] = { node = node, type = match or 'field' }
end
end
local _, _, start = node:start()
nodes_set[start] = {node = node, type = match or ""}
end)
end
end
@ -337,7 +140,7 @@ local function prepare_node(node, kind)
local matches = {}
kind = kind or node.type
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
for name, item in pairs(node) do
vim.list_extend(matches, prepare_node(item, name))
@ -347,12 +150,14 @@ local function prepare_node(node, kind)
end
local function get_scope(type, source)
local sbl, sbc, sel, sec = source:range()
local current = source
local result = current
local next = ts_utils.get_next_node(source)
local parent = current:parent()
trace(source:type(), source:range(), parent)
if type == 'method' or type:find('function') and parent ~= nil then
if type == 'method' or type == 'function' and parent ~= nil then
trace(parent:type(), parent:range())
-- a function name
if parent:type() == 'function_name' then
@ -365,7 +170,7 @@ local function get_scope(type, source)
-- for C++
local n = source
for _ = 1, 4, 1 do
for i = 1, 4, 1 do
if n == nil or n:parent() == nil then
break
end
@ -377,12 +182,8 @@ local function get_scope(type, source)
return parent, true
end
if type == 'var' and next ~= nil then
if
next:type() == 'function'
or next:type() == 'arrow_function'
or next:type() == 'function_definition'
then
if type == "var" and next ~= nil then
if next:type() == "function" or next:type() == "arrow_function" or next:type() == "function_definition" then
trace(current:type(), current:range())
return next, true
elseif parent:type() == 'function_declaration' then
@ -395,7 +196,7 @@ local function get_scope(type, source)
-- M.fun1 = function() end
-- lets work up and see next node, lua
local n = source
for _ = 1, 4, 1 do
for i = 1, 4, 1 do
if n == nil or n:parent() == nil then
break
end
@ -407,9 +208,10 @@ local function get_scope(type, source)
end
end
if source:type() == 'type_identifier' then
if source:type() == "type_identifier" then
return source:parent(), true
end
end
local function get_smallest_context(source)
@ -427,28 +229,14 @@ local function get_smallest_context(source)
-- if source:type() == "identifier" then return get_var_context(source) end
end
local lsp_reference = require('navigator.dochighlight').goto_adjent_reference
local function index_of(tbl, obj)
for i, o in ipairs(tbl) do
if o == obj then
return i
end
end
end
local lsp_reference = require"navigator.dochighlight".goto_adjent_reference
function M.goto_adjacent_usage(bufnr, delta)
local opt = { forward = delta > 0 }
local opt = {forward = true}
-- log(delta)
local en = _NgConfigValues.treesitter_navigation
if type(en) == 'table' then
en = vim.tbl_contains(en, vim.o.ft)
if delta < 0 then
opt.forward = false
end
if en == false then
return lsp_reference(opt)
end
bufnr = bufnr or api.nvim_get_current_buf()
local node_at_point = ts_utils.get_node_at_cursor()
if not node_at_point then
@ -458,9 +246,8 @@ function M.goto_adjacent_usage(bufnr, delta)
local def_node, scope = ts_locals.find_definition(node_at_point, bufnr)
local usages = ts_locals.find_usages(def_node, scope, bufnr)
trace(usages)
local index = index_of(usages, node_at_point)
local index = utils.index_of(usages, node_at_point)
if not index then
lsp_reference(opt)
return
@ -482,7 +269,7 @@ local function key(fname, filter)
end
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)
if bufnr ~= 0 then
uri = vim.uri_from_bufnr(bufnr)
@ -495,8 +282,7 @@ local function get_all_nodes(bufnr, filter, summary)
local result = lru:get(hash)
if result ~= nil and result.ftime == ftime then
trace('get data from cache', ftime, result)
log("get data from cache")
return result.nodes, result.length
end
@ -506,35 +292,32 @@ local function get_all_nodes(bufnr, filter, summary)
trace(bufnr, filter, summary)
if not bufnr then
vim.notify('get_all_node invalid bufnr', vim.log.levels.WARN)
vim.notify("get_all_node invalide bufnr", vim.lsp.log_levels.WARN)
end
summary = summary or false
local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
if not parsers.has_parser() then
if not require('navigator.lspclient.clients').ft_disabled(ft) then
-- vim.notify('ts not loaded ' .. ft, vim.log.levels.Debug)
log('ts not loaded ' .. ft)
end
return {}
vim.notify("ts not loaded", vim.lsp.log_levels.WARN)
end
local path_sep = require('navigator.util').path_sep()
local path_cur = require('navigator.util').path_cur()
local path_sep = require"navigator.util".path_sep()
local path_cur = require"navigator.util".path_cur()
local display_filename = fname:gsub(cwd .. path_sep, path_cur, 1)
local all_nodes = {}
local containers = filter
or {
['function'] = true,
['local_function'] = true,
['arrow_function'] = true,
['type'] = true,
['class'] = true,
['call_expression'] = true,
-- ['var'] = true,
['struct'] = true,
['method'] = true,
}
-- Support completion-nvim customized label map
local customized_labels = vim.g.completion_customize_lsp_label or {}
-- Force some types to act like they are parents
-- instead of neighbors of the next nodes.
local containers = {
["function"] = true,
["local_function"] = true,
["arrow_function"] = true,
["type"] = true,
["class"] = true,
["struct"] = true,
["method"] = true
}
-- check and load buff
@ -547,31 +330,15 @@ local function get_all_nodes(bufnr, filter, summary)
-- Step 2 find correct completions
local length = 10
local parents = {} -- stack of nodes a clever algorithm from treesiter refactor @Santos Gallegos
local loaded_symbol = {}
for _, def in ipairs(get_definitions(bufnr)) do
local n = #parents
for i = 1, n do
local index = n + 1 - i
local parent_def = parents[index]
-- trace(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr))
-- trace(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr))
if
ts_utils.is_parent(parent_def.node, def.node)
or (
containers[parent_def.type]
and (
ts_utils.is_parent(parent_def.node:parent(), def.node)
or (
parent_def.node:parent():type():find('dot_index')
and ts_utils.is_parent(parent_def.node:parent():parent(), def.node)
)
)
)
then
-- trace('is parent', i, index)
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)) then
break
else
-- trace('leave node', i, index)
parents[index] = nil
end
end
@ -584,24 +351,15 @@ local function get_all_nodes(bufnr, filter, summary)
item.type = node.type
if filter ~= nil and not filter[item.type] then
trace('skipped', item.type, item.kind)
goto continue
end
if item.type == 'associated' then
trace('skipped', item.type, item.kind)
trace(item.type, item.kind)
goto continue
end
local tsdata = node.def
if node.def == nil then
trace('skipped', item.type, item.kind)
goto continue
end
local text = vim.treesitter.get_node_text(tsdata, bufnr) or ''
text = vim.split(text, '\n')[1] or ''
item.node_text = text
log(item.node_text)
item.node_text = ts_utils.get_node_text(tsdata, bufnr)[1]
local scope, is_func
if summary then
@ -609,66 +367,41 @@ local function get_all_nodes(bufnr, filter, summary)
else
scope, is_func = get_smallest_context(tsdata)
end
log(item, scope, is_func)
if is_func then
-- hack for lua and maybe other language aswell
local parent = tsdata:parent()
if parent ~= nil and _NgConfigValues.debug == 'trace' then -- for github action failure
-- stylua: ignore start
trace( parent:type(), vim.treesitter.get_node_text(parent, bufnr):sub(1, 30), item.node_text, item.type)
-- stylua: ignore end
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
if parent ~= nil and parent:type() == 'function_name' or parent:type() == 'function_name_field' then
item.node_text = ts_utils.get_node_text(parent, bufnr)[1]
log(parent:type(), item.node_text)
end
end
trace(item.node_text, item.kind, item.type)
if scope ~= nil then
-- it is strange..
if not is_func and summary then
trace('skipped', item.node_text, item.type)
goto continue
end
item.node_scope = ts_utils.node_to_lsp_range(scope)
end
if item.node_text and vim.trim(item.node_text) == '_' then
goto continue
end
if summary then
if item.node_scope ~= nil then
table.insert(all_nodes, item)
end
if item.node_scope then
-- stylua: ignore start
trace( 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
-- stylua: ignore end
trace(item.type, tsdata:type(), item.node_text, item.kind, item.node_text, "range",
item.node_scope.start.line, item.node_scope['end'].line) -- set to log if need to trace result
end
goto continue
end
item.range = ts_utils.node_to_lsp_range(tsdata)
local start_line_node, _, _ = tsdata:start()
local line_text = api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1]
or ''
item.full_text = vim.trim(line_text)
if item.node_text == "_" then
goto continue
end
item.full_text = vim.trim(api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] or "")
item.full_text = item.full_text:gsub('%s*[%[%(%{]*%s*$', '')
item.uri = uri
@ -678,78 +411,45 @@ local function get_all_nodes(bufnr, filter, summary)
item.lnum, item.col, _ = def.node:start()
item.lnum = item.lnum + 1
item.col = item.col + 1
local indent = ''
local indent = ""
if #parents > 1 then
indent = string.rep(' ', #parents - 1) .. ''
end
item.indent = indent
item.indent_level = #parents -- maybe use real indent level ?
if item.indent_level <= 1 then
local sp = string.match(line_text, '(%s*)')
log(line_text, #sp)
if sp then
local indent_level = #sp / (vim.o.shiftwidth or 4) + 1
item.indent_level = math.max(item.indent_level, indent_level)
end
end
if #parents > 0 then
log(parents[1].type, vim.treesitter.get_node_text(parents[1].node, bufnr))
if parents[2] then
log(parents[2].type, vim.treesitter.get_node_text(parents[2].node, bufnr))
end
else
log('root node')
end
if #all_nodes >= 1 then
all_nodes[#all_nodes].next_indent_level = #parents
indent = string.rep(" ", #parents - 1) .. ""
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
length = #item.text
end
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
table.insert(all_nodes, item)
::continue::
end
end
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)
if should_unload then
vim.api.nvim_buf_delete(bufnr, { unload = true })
vim.api.nvim_buf_delete(bufnr, {unload = true})
end
return all_nodes, length
end
function M.buf_func(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if vim.api.nvim_buf_get_option(bufnr, 'buftype') == 'nofile' then
return
end
if not ok or ts_locals == nil then
error('treesitter not loaded: ' .. ft)
error("treesitter not loaded")
return
end
bufnr = bufnr or api.nvim_get_current_buf()
local all_nodes, width = get_all_nodes(bufnr, {
['function'] = true,
['arrow_function'] = true,
['var'] = true,
['method'] = true,
['class'] = true,
['type'] = true,
["function"] = true,
["var"] = true,
["method"] = true,
["class"] = true,
["type"] = true
}, true)
if #all_nodes < 1 then
trace('no node found for ', bufnr) -- set to log
trace("no node found for ", bufnr) -- set to log
return
end
@ -776,66 +476,36 @@ function M.buf_func(bufnr)
return false
end)
end
log(all_nodes)
return all_nodes, width
end
function M.all_ts_nodes(bufnr)
function M.buf_ts()
if ts_locals == nil then
error('treesitter not loaded')
error("treesitter not loaded")
return
end
bufnr = bufnr or api.nvim_get_current_buf()
local all_nodes, width = get_all_nodes(bufnr)
return all_nodes, width
end
function M.side_panel()
Panel = require('guihua.panel')
local bufnr = api.nvim_get_current_buf()
local panel = Panel:new({
header = 'treesitter',
render = function(b)
local ft = vim.api.nvim_buf_get_option(b, 'buftype')
log('render for ', bufnr, b)
if ft == 'nofile' or ft == 'guihua' then
b = bufnr
end
return require('navigator.treesitter').all_ts_nodes(b)
end,
scope = 'node_scope',
})
panel:open(true)
end
local all_nodes, width = get_all_nodes(bufnr)
function M.buf_ts()
local all_nodes, width = M.all_ts_nodes()
if vim.fn.empty(all_nodes) == 1 then
return vim.notify('no treesitter node found')
end
local bufnr = api.nvim_get_current_buf()
local ft = vim.api.nvim_buf_get_option(bufnr, 'ft')
local listview = gui.new_list_view({
local ft = vim.api.nvim_buf_get_option(bufnr, "ft")
gui.new_list_view({
items = all_nodes,
prompt = true,
ft = ft,
rawdata = true,
height = 0.62,
preview_height = 0.12,
width = (width or 80) + 10,
title = 'treesitter symbols',
api = _NgConfigValues.icons.treesitter_defult,
width = width + 10,
api = _NgConfigValues.icons.treesitter_defult
})
return listview, all_nodes, width
end
M.get_all_nodes = get_all_nodes
function M.bufs_ts()
if ts_locals == nil then
error('treesitter not loaded')
error("treesitter not loaded")
return
end
local bufs = vim.api.nvim_list_bufs()
@ -858,16 +528,13 @@ function M.bufs_ts()
if #ts_opened > 1 then
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({
items = ts_opened,
prompt = true,
ft = ft,
height = 0.62,
preview_height = 0.12,
width = max_length + 10,
title = 'treesitter symbols',
api = _NgConfigValues.icons.treesitter_defult,
api = _NgConfigValues.icons.treesitter_defult
})
end
end
@ -876,7 +543,7 @@ local function node_in_range(parser, range)
for _, child in pairs(parser._children) do
if child:contains(range) then
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())
return parser
end
@ -897,7 +564,7 @@ function M.get_node_at_line(lnum)
lnum = cursor[1]
end
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
local root = parsers.get_parser()
@ -911,7 +578,7 @@ function M.get_node_at_line(lnum)
return node
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)
M.clear_usage_highlights(bufnr)
@ -928,12 +595,12 @@ function M.highlight_usages(bufnr)
for _, usage_node in ipairs(usages) do
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
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
@ -943,21 +610,16 @@ end
function M.get_node_at_pos(pos, parser)
-- 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(pos)
local root = ts_utils.get_root_for_position(pos[1], pos[2], parser)
log(cursor_range)
local root = ts_utils.get_root_for_position(unpack(cursor_range), parser)
if not root then
return
end
local node = root:named_descendant_for_range(
cursor_range[1],
cursor_range[2],
cursor_range[1],
cursor_range[2]
)
local node = root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
log(node, node:range())
return node
end
@ -989,6 +651,7 @@ function M.get_node_scope(node)
end
return sr, sc, er, ec
end
return M

@ -3,16 +3,11 @@
-- Some of function copied from https://github.com/RishabhRD/nvim-lsputils
local M = { log_path = vim.lsp.get_log_path() }
-- local is_windows = uv.os_uname().version:match("Windows")
pcall(require, 'guihua') -- lazy load
local guihua = require('guihua.util')
local nvim_0_8
local vfn = vim.fn
local api = vim.api
local uv = vim.uv or vim.loop
local os_name = uv.os_uname().sysname
local is_win = os_name:find('Windows') or os_name:find('MINGW')
local nvim_0_6
M.path_sep = function()
local is_win = vim.loop.os_uname().sysname:find('Windows')
if is_win then
return '\\'
else
@ -23,6 +18,7 @@ end
local path_sep = M.path_sep()
M.path_cur = function()
local is_win = vim.loop.os_uname().sysname:find('Windows')
if is_win then
return '.\\'
else
@ -30,9 +26,8 @@ M.path_cur = function()
end
end
M.round = function(x, r)
r = r or 0.5
return math.max(0, math.floor(x - r))
M.round = function(x)
return math.max(0, math.floor(x - 0.5))
end
function M.get_data_from_file(filename, startLine)
@ -46,10 +41,10 @@ function M.get_data_from_file(filename, startLine)
end
local uri = 'file:///' .. filename
local bufnr = vim.uri_to_bufnr(uri)
if not api.nvim_buf_is_loaded(bufnr) then
vfn.bufload(bufnr)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
end
local data = api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
local data = vim.api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
if data == nil or vim.tbl_isempty(data) then
startLine = nil
else
@ -63,29 +58,6 @@ function M.get_data_from_file(filename, startLine)
return { data = data, line = displayLine }
end
function M.io_read(filename)
local f = io.open(filename, 'r')
if f == nil then
return nil
end
local content = f:read('*a') -- *a or *all reads the whole file
f:close()
return content
end
function M.rm_file(filename)
return os.remove(filename)
end
function M.file_exists(name)
local f = io.open(name, 'r')
if f ~= nil then
io.close(f)
return true
end
return false
end
M.merge = function(t1, t2)
for k, v in pairs(t2) do
t1[k] = v
@ -104,9 +76,9 @@ M.map = function(modes, key, result, options)
for i = 1, #modes do
if buffer then
api.nvim_buf_set_keymap(0, modes[i], key, result, options)
vim.api.nvim_buf_set_keymap(0, modes[i], key, result, options)
else
api.nvim_set_keymap(modes[i], key, result, options)
vim.api.nvim_set_keymap(modes[i], key, result, options)
end
end
end
@ -119,7 +91,6 @@ function M.get_base(path)
return ret
end
end
return ''
end
local function getDir(path)
@ -141,29 +112,16 @@ local function getDir(path)
end
function M.get_relative_path(base_path, my_path)
M.trace('rel path', base_path, my_path)
base_path = string.lower(base_path)
my_path = string.lower(my_path)
local base_data = getDir(base_path)
if base_data == nil then
M.log('base data is nil')
return
end
local my_data = getDir(my_path)
if vim.fn.empty(my_data) == 1 then
M.log('my data is nil', my_path)
return
end
local base_len = #base_data
local my_len = #my_data
if base_len > my_len then
M.log('incorrect dir format: base data', base_data, 'my data', my_data)
return my_path
end
if base_data[1] ~= my_data[1] then
M.log('base data is not same', base_data[1], my_data[1])
return my_path
end
@ -182,38 +140,24 @@ function M.get_relative_path(base_path, my_path)
return data
end
M.log = function(...)
return { ... }
local level = 'error'
if _NgConfigValues.debug == true then
level = 'info'
elseif _NgConfigValues.debug == 'trace' then
level = 'trace'
end
M.trace = function(...)
return { ... }
local default_config = { use_console = false, use_file = true, level = level }
if _NgConfigValues.debug_console_output then
default_config.use_console = true
default_config.use_file = false
end
M._log = require('guihua.log').new(default_config, true)
local level = 'info'
function M.setup()
if _NgConfigValues.debug == true then
level = 'debug'
elseif _NgConfigValues.debug == 'trace' then
level = 'trace'
end
local default_config =
{ use_console = false, use_file = true, level = level, plugin = 'navigator' }
if _NgConfigValues.debug_console_output then
default_config.use_console = true
default_config.use_file = false
end
M._log = require('guihua.log').new(default_config, true)
if _NgConfigValues.debug then
-- add log to you lsp.log
M.trace = M._log.trace
M.info = M._log.info
M.warn = M._log.warn
M.error = M._log.error
M.log = M.info
end
end
-- add log to you lsp.log
M.log = M._log.info
M.info = M._log.info
M.trace = M._log.trace
M.error = M._log.error
function M.fmt(...)
M._log.fmt_info(...)
@ -277,7 +221,7 @@ function M.printError(msg)
end
function M.reload()
vim.lsp.stop_client(vim.lsp.get_clients())
vim.lsp.stop_client(vim.lsp.get_active_clients())
vim.cmd([[edit]])
end
@ -285,11 +229,11 @@ function M.open_log()
local path = vim.lsp.get_log_path()
vim.cmd('edit ' .. path)
end
if not table.pack then
table.pack = function(...)
return { n = select('#', ...), ... }
end
function table.pack(...)
return { n = select('#', ...), ... }
end
function M.show(...)
local string = ''
@ -307,7 +251,7 @@ function M.split2(s, sep)
sep = sep or ' '
local pattern = string.format('([^%s]+)', sep)
_ = string.gsub(s, pattern, function(c)
string.gsub(s, pattern, function(c)
fields[#fields + 1] = c
end)
@ -334,18 +278,30 @@ function M.trim_and_pad(txt)
end
M.open_file = function(filename)
api.nvim_command(string.format('e! %s', filename))
vim.api.nvim_command(string.format('e! %s', filename))
end
M.open_file_at = guihua.open_file_at
M.open_file_at = function(filename, line, col, split)
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)
-- for k, _ in pairs(_G) do
-- if k == var then
-- return true
-- end
-- end
-- end
function M.exists(var)
for k, _ in pairs(_G) do
if k == var then
return true
end
end
end
local exclude_ft = { 'scrollbar', 'help', 'NvimTree' }
function M.exclude(fname)
@ -361,6 +317,7 @@ end
-- name space search
local nss
local api = vim.api
local bufs
function M.set_virt_eol(bufnr, lnum, chunks, priority, id)
@ -370,13 +327,7 @@ function M.set_virt_eol(bufnr, lnum, chunks, priority, id)
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
bufs[bufnr] = true
-- id may be nil
return api.nvim_buf_set_extmark(
bufnr,
nss,
lnum,
-1,
{ id = id, virt_text = chunks, priority = priority }
)
return api.nvim_buf_set_extmark(bufnr, nss, lnum, -1, { id = id, virt_text = chunks, priority = priority })
end
function M.clear_buf(bufnr)
@ -404,46 +355,40 @@ function M.get_current_winid()
return api.nvim_get_current_win()
end
function M.nvim_0_8()
if nvim_0_8 ~= nil then
return nvim_0_8
function M.nvim_0_6()
if nvim_0_6 ~= nil then
return nvim_0_6
end
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')
vim.notify('Please use navigator 0.4 version for neovim version < 0.8', vim.log.levels.ERROR)
if debug.getinfo(vim.lsp.handlers.signature_help).nparams == 4 then
nvim_0_6 = true
else
nvim_0_6 = false
end
return nvim_0_8
return nvim_0_6
end
function M.mk_handler(fn)
return function(...)
return fn(...)
local config_or_client_id = select(4, ...)
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
function M.partial(func, arg)
return function(...)
return (M.mk_handler(function(...)
return func(arg, ...)
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)
@ -458,19 +403,18 @@ function M.empty(t)
end
function M.encoding(client)
if client == nil then
client = 1
end
if type(client) == 'number' then
client = vim.lsp.get_client_by_id(client) or {}
if type(client) ~= 'table' then
if client == nil then
client = 1
end
client = vim.lsp.get_client_by_id(client)
end
local oe = client.offset_encoding
if oe == nil then
return 'utf-8'
end
if type(oe) == 'table' then
return oe[1]
oe = oe[1] or 'utf-8'
end
return oe
end
@ -478,153 +422,15 @@ end
-- alternatively: use vim.notify("namespace does not exist or is anonymous", vim.log.levels.ERROR)
function M.warn(msg)
vim.notify('WRN: ' .. msg, vim.log.levels.WARN)
vim.api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
end
function M.error(msg)
vim.notify('ERR: ' .. msg, vim.log.levels.EROR)
vim.api.nvim_echo({ { 'ERR: ' .. msg, 'ErrorMsg' } }, true, {})
end
function M.info(msg)
vim.notify('INF: ' .. msg, vim.log.levels.INFO)
end
function M.dedup(locations)
local m = math.min(10, #locations) -- dedup first 10 elements
local dict = {}
local del = {}
for i = 1, m, 1 do
local value = locations[i]
local range = value.range or value.originSelectionRange or value.targetRange
if not range then
break
end
local key = (value.uri or range.uri or value.targetUri or '')
.. ':'
.. tostring(range.start.line)
.. ':'
.. tostring(range.start.character)
.. ':'
.. tostring(range['end'].line)
.. ':'
.. tostring(range['end'].character)
if dict[key] == nil then
dict[key] = i
else
local j = dict[key]
if not locations[j].definition then
table.insert(del, i)
else
table.insert(del, j)
end
end
end
table.sort(del)
for i = #del, 1, -1 do
M.log('remove ', del[i])
table.remove(locations, del[i])
end
return locations
end
function M.range_inside(outer, inner)
if outer == nil or inner == nil then
return false
end
if outer.start == nil or outer['end'] == nil or inner.start == nil or inner['end'] == nil then
return false
end
return outer.start.line <= inner.start.line and outer['end'].line >= inner['end'].line
end
function M.dirname(pathname)
local strip_dir_pat = path_sep .. '([^' .. path_sep .. ']+)$'
local strip_sep_pat = path_sep .. '$'
if not pathname or #pathname == 0 then
return
end
local result = pathname:gsub(strip_sep_pat, ''):gsub(strip_dir_pat, '')
if #result == 0 then
return '/'
end
return result
end
function M.sub_match(str)
local _, j = string.gsub(str, [["]], '')
if j % 2 == 1 then
str = str .. '"'
end
_, j = string.gsub(str, [[']], '')
if j % 2 == 1 then
str = str .. [[']]
end
str = str .. '󰇘'
return str
end
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match('^```(.*)')
if language_id then
local has_inner_code_fence = false
for i = 2, (#lines - 1) do
local line = lines[i]
if line:sub(1, 3) == '```' then
has_inner_code_fence = true
break
end
end
-- No inner code fences + starting with code fence = hooray.
if not has_inner_code_fence then
table.remove(lines, 1)
table.remove(lines)
return language_id
end
end
return 'markdown'
end
function M.trim_empty_lines(lines)
local new_list = {}
for i, str in ipairs(lines) do
if str ~= '' and str then
table.insert(new_list, str)
end
end
return new_list
end
function M.for_each_buffer_client(bufnr, fn)
local clients
if vim.lsp.get_clients then -- nightly nvim 0.10
clients = vim.lsp.get_clients({ bufnr = bufnr })
else
clients = vim.lsp.buf_get_clients()
end
for _, client in pairs(clients) do
fn(client, client.id, bufnr)
end
end
function M.binding_remap(fn, key)
return function(...)
if fn(...) ~= true and key then -- the function failed fallback to key
M.log(key)
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, false, true), 'n', true)
end
end
end
function M.mk_handler_remap(fn, fallback)
return function(...)
if fn(...) ~= true then -- the function failed fallback to key
M.log('fallback, ', fallback)
if fallback then
M.log('fallback')
fallback()
end
end
end
vim.api.nvim_echo({ { 'Info: ' .. msg } }, true, {})
end
return M

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

@ -12,14 +12,13 @@ most used plugins for programmer.
- luasnip
- aurora (colorscheme used in the screenshot)
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.
There also three folder `js`, `go`, `py`. Those folder have some basic source code you can play with.
## Install LSP
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
potint to ~/github/sumneko if not existed in your PATH.
potint to ~/github/sumneko
## run init.lua

@ -1,43 +0,0 @@
#include <iostream>
#include <string>
#include <unordered_map>
int main()
{
// Create an unordered_map of three strings (that map to strings)
std::unordered_map<std::string, std::string> u =
{
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
};
// Helper lambda function to print key-value pairs
auto print_key_value = [](const auto& key, const auto& value)
{
std::cout << "Key:[" << key << "] Value:[" << value << "]\n";
};
std::cout << "Iterate and print key-value pairs of unordered_map, being\n"
"explicit with their types:\n";
for (const std::pair<const std::string, std::string>& n : u)
print_key_value(n.first, n.second);
std::cout << "\nIterate and print key-value pairs using C++17 structured binding:\n";
for (const auto& [key, value] : u)
print_key_value(key, value);
// Add two new entries to the unordered_map
u["BLACK"] = "#000000";
u["WHITE"] = "#FFFFFF";
std::cout << "\nOutput values by key:\n"
"The HEX of color RED is:[" << u["RED"] << "]\n"
"The HEX of color BLACK is:[" << u["BLACK"] << "]\n\n";
std::cout << "Use operator[] with non-existent key to insert a new key-value pair:\n";
print_key_value("new_key", u["new_key"]);
std::cout << "\nIterate and print key-value pairs, using `auto`;\n"
"new_key is now one of the keys in the map:\n";
for (const auto& n : u)
print_key_value(n.first, n.second);
}

@ -1,157 +1,117 @@
vim.cmd([[set runtimepath=$VIMRUNTIME]])
local uv = vim.uv or vim.loop
local os_name = uv.os_uname().sysname
vim.cmd([[set packpath=/tmp/nvim/site]])
local is_windows = os_name == 'Windows' or os_name == 'Windows_NT'
local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'
local package_root = '/tmp/nvim/lazy'
local sep = '/'
if is_windows then
local tmp = os.getenv('TEMP')
vim.cmd('set packpath=' .. tmp .. '\\nvim\\lazy')
package_root = tmp .. '\\nvim\\lazy'
sep = '\\'
else
vim.cmd([[set packpath=/tmp/nvim/lazy]])
end
-- IMPORTANT: update the sumneko setup if you need lua language server
-- I installed it in '/github/sumneko/lua-language-server'
local sumneko_root_path = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server'
local sumneko_binary = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server/bin/macOS/lua-language-server'
local plugin_folder = function()
local host = os.getenv('HOST_NAME')
if host and (host:find('Ray') or host:find('ray')) then
return [[~/github/ray-x]] -- vim.fn.expand("$HOME") .. '/github/'
else
return ''
end
end
local lua_cfg = {
cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' },
settings = {
Lua = {
runtime = { version = 'LuaJIT', path = vim.split(package.path, ';') },
diagnostics = { enable = true },
},
},
}
local lazypath = package_root .. sep .. 'lazy.nvim'
if not uv.fs_stat(lazypath) then
vim.fn.system({
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
local function load_plugins()
return {
{
'nvim-treesitter/nvim-treesitter',
config = function()
require('nvim-treesitter.configs').setup({
ensure_installed = { 'go' },
highlight = { enable = true },
})
end,
build = ':TSUpdate',
},
{ 'neovim/nvim-lspconfig' },
-- {
-- 'simrat39/rust-tools.nvim',
-- config = function()
-- 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,
-- },
-- })
-- end,
-- },
{ 'ray-x/lsp_signature.nvim', dev = (plugin_folder() ~= '') },
{
'ray-x/navigator.lua',
dev = (plugin_folder() ~= ''),
-- '~/github/ray-x/navigator.lua',
dependencies = { 'ray-x/guihua.lua', build = 'cd lua/fzy && make' },
config = function()
require('navigator').setup({
keymaps = {
{
key = '<Leader>rn',
func = require('navigator.rename').rename,
desc = 'rename',
require('packer').startup({
function(use)
use({ 'wbthomason/packer.nvim' })
use({
'nvim-treesitter/nvim-treesitter',
config = function()
require('nvim-treesitter.configs').setup({
ensure_installed = { 'python', 'go', 'javascript' },
highlight = { enable = true },
})
end,
run = ':TSUpdate',
})
use({ 'neovim/nvim-lspconfig' })
use({ 'ray-x/lsp_signature.nvim' })
use({ 'ray-x/aurora' })
use({
'ray-x/navigator.lua',
-- '~/github/navigator.lua',
requires = { 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
config = function()
require('navigator').setup({
lsp_signature_help = true,
})
end,
})
use({ 'L3MON4D3/LuaSnip' })
use({
'hrsh7th/nvim-cmp',
requires = {
'hrsh7th/cmp-nvim-lsp',
'saadparwaiz1/cmp_luasnip',
},
config = function()
local cmp = require('cmp')
local luasnip = require('luasnip')
cmp.setup({
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
},
lsp = {
-- disable_lsp = { 'rust_analyzer', 'clangd' },
},
})
end,
},
{
'hrsh7th/nvim-cmp',
dependencies = {
'neovim/nvim-lspconfig',
'hrsh7th/cmp-nvim-lsp',
},
config = function()
-- Add additional capabilities supported by nvim-cmp
local cmp = require('cmp')
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
['<C-u>'] = cmp.mapping.scroll_docs(-4), -- Up
['<C-d>'] = cmp.mapping.scroll_docs(4), -- Down
-- C-b (back) C-f (forward) for snippet placeholder navigation.
['<C-Space>'] = cmp.mapping.complete(),
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
}),
sources = {
{ name = 'nvim_lsp' },
},
})
end,
},
{
'ray-x/go.nvim',
dev = (plugin_folder() ~= ''),
-- dev = true,
ft = 'go',
dependencies = {
'mfussenegger/nvim-dap', -- Debug Adapter Protocol
'rcarriga/nvim-dap-ui',
'theHamsta/nvim-dap-virtual-text',
'ray-x/guihua.lua',
},
config = function()
require('go').setup({
verbose = true,
lsp_cfg = {
handlers = {
['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = 'double' }),
['textDocument/signatureHelp'] = vim.lsp.with(
vim.lsp.handlers.signature_help,
{ border = 'round' }
),
mapping = {
['<CR>'] = cmp.mapping.confirm({ select = true }),
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.confirm({ select = true })
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { 'i', 's' }),
},
}, -- false: do nothing
})
end,
sources = {
{ name = 'nvim_lsp' },
{ name = 'buffer' },
},
})
require('cmp').setup.cmdline(':', {
sources = {
{ name = 'cmdline' },
},
})
require('cmp').setup.cmdline('/', {
sources = {
{ name = 'buffer' },
},
})
end,
})
end,
config = {
package_root = package_root,
compile_path = install_path .. '/plugin/packer_compiled.lua',
},
}
})
end
local opts = {
root = package_root, -- directory where plugins will be installed
default = { lazy = true },
dev = {
-- directory where you store your local plugin projects
path = plugin_folder(),
},
}
require('lazy').setup(load_plugins(), opts)
vim.cmd('colorscheme murphy')
if vim.fn.isdirectory(install_path) == 0 then
vim.fn.system({
'git',
'clone',
'https://github.com/wbthomason/packer.nvim',
install_path,
})
load_plugins()
require('packer').sync()
vim.cmd('colorscheme aurora')
else
load_plugins()
vim.cmd('colorscheme aurora')
end

@ -1,61 +0,0 @@
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

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

@ -1,14 +0,0 @@
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 ])

@ -1,9 +0,0 @@
[package]
name = "hello"
version = "0.1.0"
authors = ["Ray-X <rayx.cn@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

@ -1,89 +0,0 @@
use std::io;
trait Show {
fn show(&self) -> String;
}
impl Show for i32 {
fn show(&self) -> String {
format!("four-byte signed {}", self)
}
}
impl Show for f64 {
fn show(&self) -> String {
format!("eight-byte float {}", self)
}
}
fn another_function(x: i32, y: i32) {
println!("The value of x is: {}, y {}", x, y);
}
fn fun1(x: i32, y: i32) {
println!("The value of x is: {}, y {}", x, y);
}
impl<Iter> Iterator for Iter
where Iter: Iterator,
{
type Item = i32;
fn next(&mut self) -> Option<i32> {
Some(42)
}
}
fn add(left: i32, right: i32) -> i32 {
return left + right;
}
fn add4(left: i32, right: i32, t: i32, f: i32) -> i32 {
return left + right + t + f;
}
struct Foo<'a> {
x: &'a i32,
}
struct Boo<'b> {
x: &'b i32,
}
const CAMEL_CASE: i32 = 42;
fn bug(left: i32, rigth: i32) -> i32 {
return left;
}
fn test_signature(a: i32, b: i32, c: i32) -> i32 {
a + b - c
}
fn test(a: i32) {}
fn test2() {
test(1)
}
fn test3() {
test(1);
test2()
}
fn main() {
test_signature(1, 2, 3);
let x = || 42;
bug(x(), 32);
bug(x(), 32);
add(add(1, 2), 3);
add(add(1, 2), 3);
let answer = 42;
let maybe_pi = 3.14;
let v: Vec<&Show> = vec![&answer, &maybe_pi];
for d in v.iter() {
println!("show {}", d.show());
}
add4(1, 2, 3, add(1, 2));
add4(add(1, 2), 3, add(3, 4), 4);
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let f = Foo { x: y };
let z = &5; // this is the same as `let _y = 5; let y = &_y;`
let f22 = Boo { x: z };
another_function(11, 2);
}

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

@ -1,69 +0,0 @@
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_clients()) do
if client.name == 'gopls' then
found = true
break
end
end
if found then
break
end
end
it('should show panel', function()
vim.fn.setpos('.', { bufn, 24, 15, 0 })
require('navigator.hierarchy').incoming_calls_panel()
vim.wait(300, function() end)
local panel = require('guihua.panel').debug()
eq(panel.name, 'Panel')
vim.wait(500, function() end)
panel = require('guihua.panel').debug()
print(vim.inspect(panel))
-- eq(
-- panel.activePanel.sections[1].header[1],
-- '──────────Call Hierarchy──────────'
-- )
-- eq(panel.activePanel.sections[1].nodes[1].name, 'measure')
end)
it('should not crash and show hierarchy', function()
vim.fn.setpos('.', { bufn, 24, 15, 0 })
local ret = require('navigator.hierarchy')._call_hierarchy()
vim.wait(400, function() end)
eq(ret, ret) -- make sure doesn't crash the result
end)
end)

@ -40,7 +40,7 @@ require'lspconfig'.gopls.setup{}
require'navigator'.setup({
debug = false, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons={code_action_icon = ""},
icons={code_action_icon = ""},
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

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

@ -1,217 +0,0 @@
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_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)

@ -17,5 +17,4 @@ local func = function(p, uv)
assert(elapsed >= 1000, "elapsed should be at least delay ")
end
local uv = vim.uv or vim.loop
func(print, uv)
func(print, vim.loop)

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

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