aboutsummaryrefslogtreecommitdiff
path: root/autoload
diff options
context:
space:
mode:
authorYasuhiro Matsumoto <mattn.jp@gmail.com>2020-01-30 00:31:25 +0900
committerYasuhiro Matsumoto <mattn.jp@gmail.com>2020-01-30 00:31:25 +0900
commitf14f0f7cb62855844fcdac60911c279813d3cd05 (patch)
treee36fe56dd26f4c81e51c3906b9c2b3dafb235177 /autoload
parentf76f655e5733ec766db2d627c6ec01beeade3590 (diff)
downloadvim-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.vim298
-rw-r--r--autoload/lsp_settings/utils.vim27
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