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