diff options
author | Yasuhiro Matsumoto <mattn.jp@gmail.com> | 2020-01-30 00:31:25 +0900 |
---|---|---|
committer | Yasuhiro Matsumoto <mattn.jp@gmail.com> | 2020-01-30 00:31:25 +0900 |
commit | f14f0f7cb62855844fcdac60911c279813d3cd05 (patch) | |
tree | e36fe56dd26f4c81e51c3906b9c2b3dafb235177 /autoload | |
parent | f76f655e5733ec766db2d627c6ec01beeade3590 (diff) | |
download | vim-lsp-settings-f14f0f7cb62855844fcdac60911c279813d3cd05.tar.gz vim-lsp-settings-f14f0f7cb62855844fcdac60911c279813d3cd05.tar.bz2 vim-lsp-settings-f14f0f7cb62855844fcdac60911c279813d3cd05.zip |
Testable
Diffstat (limited to 'autoload')
-rw-r--r-- | autoload/lsp_settings.vim | 298 | ||||
-rw-r--r-- | autoload/lsp_settings/utils.vim | 27 |
2 files changed, 304 insertions, 21 deletions
diff --git a/autoload/lsp_settings.vim b/autoload/lsp_settings.vim index 0e11c0a..429aa5a 100644 --- a/autoload/lsp_settings.vim +++ b/autoload/lsp_settings.vim @@ -1,7 +1,81 @@ +let s:settings_dir = expand('<sfile>:h:h').'/settings' +let s:checkers_dir = expand('<sfile>:h:h').'/checkers' let s:servers_dir = expand('<sfile>:h:h').'/servers' let s:installer_dir = expand('<sfile>:h:h').'/installer' let s:root_dir = expand('<sfile>:h:h') +let s:settings = json_decode(join(readfile(expand('<sfile>:h:h') . '/settings.json'), "\n")) +call remove(s:settings, '$schema') + +let s:ftmap = {} + +function! s:executable(cmd) abort + if executable(a:cmd) + return 1 + endif + let l:paths = get(g:, 'lsp_settings_extra_paths', '') + if type(l:paths) == type([]) + let l:paths = join(l:paths, ',') + endif + let l:servers_dir = get(g:, 'lsp_settings_servers_dir', s:servers_dir) + let l:paths .= ',' . l:servers_dir . '/' . a:cmd + if !has('win32') + let l:found = globpath(l:paths, a:cmd) + return !empty(l:found) + endif + for l:ext in ['.exe', '.cmd', '.bat'] + if !empty(globpath(l:paths, a:cmd . l:ext)) + return 1 + endif + endfor + return 0 +endfunction + +function! s:vim_lsp_installer(ft, ...) abort + let l:ft = tolower(get(split(a:ft, '\.'), 0, '')) + let l:ft = empty(l:ft) ? '_' : l:ft + if !has_key(s:settings, l:ft) + return [] + endif + let l:server = s:settings[l:ft] + if empty(l:server) + return [] + endif + let l:found = {} + for l:conf in l:server + let l:missing = 0 + for l:require in l:conf.requires + if !s:executable(l:require) + let l:missing = 1 + break + endif + endfor + if l:missing ==# 0 + let l:found = l:conf + break + endif + endfor + if empty(l:found) + return [] + endif + let l:name = get(a:000, 0, '') + for l:conf in l:server + if !empty(l:name) && l:conf.command != l:name + continue + endif + let l:command = printf('%s/install-%s', s:installer_dir, l:conf.command) + if has('win32') + let l:command = substitute(l:command, '/', '\', 'g') . '.cmd' + else + let l:command = l:command . '.sh' + endif + if s:executable(l:command) + return [l:conf.command, l:command] + endif + endfor + return [] +endfunction + function! lsp_settings#get(name, key, default) abort let l:config = get(g:, 'lsp_settings', {}) if !has_key(l:config, a:name) @@ -24,13 +98,6 @@ function! lsp_settings#get(name, key, default) abort return l:config[a:key] endfunction -function! s:first_one(cmd) abort - if empty(a:cmd) - return '' - endif - return fnamemodify(split(a:cmd, "\n")[0], ':p') -endfunction - function! lsp_settings#exec_path(cmd) abort let l:paths = [] if has('win32') @@ -48,13 +115,13 @@ function! lsp_settings#exec_path(cmd) abort let l:path = globpath(l:paths, a:cmd) if !has('win32') if !empty(l:path) - return s:first_one(l:path) + return lsp_settings#utils#first_one(l:path) endif else for l:ext in ['.exe', '.cmd', '.bat'] let l:path = globpath(l:paths, a:cmd . l:ext) if !empty(l:path) - return s:first_one(l:path) + return lsp_settings#utils#first_one(l:path) endif endfor endif @@ -66,12 +133,12 @@ function! lsp_settings#exec_path(cmd) abort let l:servers_dir = get(g:, 'lsp_settings_servers_dir', s:servers_dir) let l:paths .= l:servers_dir . '/' . a:cmd if !has('win32') - return s:first_one(globpath(l:paths, a:cmd)) + return lsp_settings#utils#first_one(globpath(l:paths, a:cmd)) endif for l:ext in ['.exe', '.cmd', '.bat'] let l:path = globpath(l:paths, a:cmd . l:ext) if !empty(l:path) - return s:first_one(l:path) + return lsp_settings#utils#first_one(l:path) endif endfor return '' @@ -101,13 +168,10 @@ function! lsp_settings#autocd(server_info) abort endfunction function! lsp_settings#complete_uninstall(arglead, cmdline, cursorpos) abort - let l:settings = json_decode(join(readfile(s:root_dir . '/settings.json'), "\n")) - call remove(l:settings, '$schema') - let l:servers_dir = get(g:, 'lsp_settings_servers_dir', s:servers_dir) let l:installers = [] - for l:ft in keys(l:settings) - for l:conf in l:settings[l:ft] + for l:ft in keys(s:settings) + for l:conf in s:settings[l:ft] if !isdirectory(l:servers_dir . '/' . l:conf.command) continue endif @@ -118,15 +182,12 @@ function! lsp_settings#complete_uninstall(arglead, cmdline, cursorpos) abort endfunction function! lsp_settings#complete_install(arglead, cmdline, cursorpos) abort - let l:settings = json_decode(join(readfile(s:root_dir . '/settings.json'), "\n")) - call remove(l:settings, '$schema') - let l:ft = tolower(get(split(&filetype, '\.'), 0, '')) let l:ft = empty(l:ft) ? '_' : l:ft - if !has_key(l:settings, l:ft) + if !has_key(s:settings, l:ft) return [] endif - let l:server = l:settings[l:ft] + let l:server = s:settings[l:ft] if empty(l:server) return [] endif @@ -154,3 +215,198 @@ function! lsp_settings#complete_install(arglead, cmdline, cursorpos) abort endfor return filter(uniq(l:installers), 'stridx(v:val, a:arglead) == 0') endfunction + +function! s:vim_lsp_uninstall_server(command) abort + if !lsp_settings#utils#valid_name(a:command) + call lsp_settings#utils#error('Invalid server name') + return + endif + call lsp_settings#utils#msg('Uninstalling ' . a:command) + let l:servers_dir = get(g:, 'lsp_settings_servers_dir', s:servers_dir) + let l:server_install_dir = l:servers_dir . '/' . a:command + if !isdirectory(l:server_install_dir) + call lsp_settings#utils#error('Server not found') + return + endif + call delete(l:server_install_dir, 'rf') + call lsp_settings#utils#msg('Uninstalled ' . a:command) +endfunction + +" neovim passes third argument as 'exit' while vim passes only 2 arguments +function! s:vim_lsp_install_server_post(command, job, code, ...) abort + if a:code != 0 + return + endif + if s:executable(a:command) + let l:script = printf('%s/%s.vim', s:settings_dir, a:command) + if filereadable(l:script) + if has('patch-8.1.1113') + command! -nargs=1 LspRegisterServer autocmd User lsp_setup ++once call lsp#register_server(<args>) + else + command! -nargs=1 LspRegisterServer autocmd User lsp_setup call lsp#register_server(<args>) + endif + exe 'source' l:script + delcommand LspRegisterServer + doautocmd User lsp_setup + endif + endif + call lsp_settings#utils#msg('Installed ' . a:command) +endfunction + +function! s:vim_lsp_install_server(ft, command) abort + if !empty(a:command) && !lsp_settings#utils#valid_name(a:command) + call lsp_settings#utils#error('Invalid server name') + return + endif + let l:entry = s:vim_lsp_installer(a:ft, a:command) + if empty(l:entry) + call lsp_settings#utils#error('Server not found') + return + endif + let l:servers_dir = get(g:, 'lsp_settings_servers_dir', s:servers_dir) + let l:server_install_dir = l:servers_dir . '/' . l:entry[0] + if isdirectory(l:server_install_dir) + call delete(l:server_install_dir, 'rf') + endif + call mkdir(l:server_install_dir, 'p') + call lsp_settings#utils#msg('Installing ' . l:entry[0]) + if has('nvim') + split new + call termopen(l:entry[1], {'cwd': l:server_install_dir, 'on_exit': function('s:vim_lsp_install_server_post', [l:entry[0]])}) | startinsert + else + let l:bufnr = term_start(l:entry[1], {'cwd': l:server_install_dir}) + let l:job = term_getjob(l:bufnr) + if l:job != v:null + call job_setoptions(l:job, {'exit_cb': function('s:vim_lsp_install_server_post', [l:entry[0]])}) + endif + endif +endfunction + +function! s:vim_lsp_settings_suggest(ft) abort + let l:entry = s:vim_lsp_installer(a:ft) + if empty(l:entry) + return + endif + if exists(':LspInstallServer') !=# 2 + redraw! + echohl Directory + echomsg 'Please do :LspInstallServer to enable Language Server ' . l:entry[0] + echohl None + command! -nargs=? -buffer -complete=customlist,lsp_settings#complete_install LspInstallServer call s:vim_lsp_install_server(&l:filetype, <q-args>) + endif +endfunction + +function! s:vim_lsp_suggest_plugin() abort + if &ft != '' + return + endif + let l:ext = expand('%:e') + for l:ft in keys(s:settings) + for l:server in s:settings[l:ft] + if !has_key(l:server, 'vim-plugin') + continue + endif + if index(l:server['vim-plugin']['extensions'], l:ext) == -1 + continue + endif + redraw + echohl Directory + echomsg printf('Please install vim-plugin "%s" to enable Language Server', l:server['vim-plugin']['name']) + echohl None + return + endfor + endfor +endfunction + +function! s:vim_lsp_load_or_suggest(ft) abort + if get(s:ftmap, a:ft, 0) + return + endif + let l:group_name = lsp_settings#utils#group_name(a:ft) + exe 'augroup' l:group_name + autocmd! + augroup END + exe 'augroup!' l:group_name + + if has('patch-8.1.1113') + command! -nargs=1 LspRegisterServer autocmd User lsp_setup ++once call lsp#register_server(<args>) + else + command! -nargs=1 LspRegisterServer autocmd User lsp_setup call lsp#register_server(<args>) + endif + + let l:found = 0 + let l:disabled = 0 + + for l:server in s:settings[a:ft] + if lsp_settings#get(l:server.command, 'disabled', get(l:server, 'disabled', 0)) + let l:disabled += 1 + continue + endif + let l:default = get(g:, 'lsp_settings_' . a:ft, '') + if !empty(l:default) && l:default != l:server.command + continue + endif + let l:command = lsp_settings#get(l:server.command, 'cmd', l:server.command) + if type(l:command) == type([]) + let l:command = l:command[0] + endif + if !s:executable(l:command) + let l:script = printf('%s/%s.vim', s:checkers_dir, l:server.command) + if !filereadable(l:script) || has_key(l:server, 'fallback') + continue + endif + let l:server['fallback'] = '' + try + exe 'source' l:script + let l:command = LspCheckCommand() + let l:server['fallback'] = l:command + catch + finally + if exists('*LspCheckCommand') + delfunction LspCheckCommand + endif + if empty(l:server['fallback']) + continue + endif + endtry + endif + let l:script = printf('%s/%s.vim', s:settings_dir, l:server.command) + if filereadable(l:script) + exe 'source' l:script + let l:found += 1 + let s:ftmap[a:ft] = 1 + break + endif + endfor + + if l:disabled == 0 && l:found ==# 0 + call s:vim_lsp_settings_suggest(a:ft) + else + doautocmd User lsp_setup + if exists(':LspInstallServer') !=# 2 + command! -nargs=? -buffer -complete=customlist,lsp_settings#complete_install LspInstallServer call s:vim_lsp_install_server(&l:filetype, <q-args>) + endif + endif + + if exists(':LspRegisterServer') !=# 2 + delcommand LspRegisterServer + endif +endfunction + +function! lsp_settings#init() abort + for l:ft in keys(s:settings) + if has_key(g:, 'lsp_settings_whitelist') && index(g:lsp_settings_whitelist, l:ft) == -1 || empty(s:settings[l:ft]) + continue + endif + exe 'augroup' lsp_settings#utils#group_name(l:ft) + autocmd! + exe 'autocmd FileType' l:ft 'call s:vim_lsp_load_or_suggest(' string(l:ft) ')' + augroup END + endfor + augroup vim_lsp_suggest + autocmd! + autocmd BufNewFile,BufRead * call s:vim_lsp_suggest_plugin() + autocmd VimEnter * call s:vim_lsp_load_or_suggest('_') + augroup END + command! -nargs=? -complete=customlist,lsp_settings#complete_uninstall LspUninstallServer call s:vim_lsp_uninstall_server(<q-args>) +endfunction diff --git a/autoload/lsp_settings/utils.vim b/autoload/lsp_settings/utils.vim new file mode 100644 index 0000000..940acb1 --- /dev/null +++ b/autoload/lsp_settings/utils.vim @@ -0,0 +1,27 @@ +function! lsp_settings#utils#msg(msg) abort + redraw + echohl Comment + echo a:msg + echohl None +endfunction + +function! lsp_settings#utils#error(msg) abort + echohl Error + echomsg a:msg + echohl None +endfunction + +function! lsp_settings#utils#valid_name(command) abort + return a:command =~# '^[a-zA-Z0-9_-]\+$' +endfunction + +function! lsp_settings#utils#group_name(ft) abort + return printf('vim_lsp_suggest_%s', a:ft) +endfunction + +function! lsp_settings#utils#first_one(cmd) abort + if empty(a:cmd) + return '' + endif + return fnamemodify(split(a:cmd, "\n")[0], ':p') +endfunction |