Add tcp feature (#985)

* Add tcp feature

* Update doc

* Update async.vim embed

* Update doc
This commit is contained in:
mattn
2021-01-01 01:28:06 +09:00
committed by GitHub
parent 5743ae2110
commit ee854b4c55
4 changed files with 98 additions and 36 deletions

View File

@@ -412,30 +412,41 @@ function! s:ensure_start(buf, server_name, cb) abort
return return
endif endif
let l:cmd_type = type(l:server_info['cmd']) if has_key(l:server_info, 'tcp')
if l:cmd_type == v:t_list let l:tcp = l:server_info['tcp'](l:server_info)
let l:cmd = l:server_info['cmd'] let l:lsp_id = lsp#client#start({
else \ 'tcp': l:tcp,
let l:cmd = l:server_info['cmd'](l:server_info) \ 'on_stderr': function('s:on_stderr', [a:server_name]),
\ 'on_exit': function('s:on_exit', [a:server_name]),
\ 'on_notification': function('s:on_notification', [a:server_name]),
\ 'on_request': function('s:on_request', [a:server_name]),
\ })
elseif has_key(l:server_info, 'cmd')
let l:cmd_type = type(l:server_info['cmd'])
if l:cmd_type == v:t_list
let l:cmd = l:server_info['cmd']
else
let l:cmd = l:server_info['cmd'](l:server_info)
endif
if empty(l:cmd)
let l:msg = s:new_rpc_error('ignore server start since cmd is empty', { 'server_name': a:server_name })
call lsp#log(l:msg)
call a:cb(l:msg)
return
endif
call lsp#log('Starting server', a:server_name, l:cmd)
let l:lsp_id = lsp#client#start({
\ 'cmd': l:cmd,
\ 'on_stderr': function('s:on_stderr', [a:server_name]),
\ 'on_exit': function('s:on_exit', [a:server_name]),
\ 'on_notification': function('s:on_notification', [a:server_name]),
\ 'on_request': function('s:on_request', [a:server_name]),
\ })
endif endif
if empty(l:cmd)
let l:msg = s:new_rpc_error('ignore server start since cmd is empty', { 'server_name': a:server_name })
call lsp#log(l:msg)
call a:cb(l:msg)
return
endif
call lsp#log('Starting server', a:server_name, l:cmd)
let l:lsp_id = lsp#client#start({
\ 'cmd': l:cmd,
\ 'on_stderr': function('s:on_stderr', [a:server_name]),
\ 'on_exit': function('s:on_exit', [a:server_name]),
\ 'on_notification': function('s:on_notification', [a:server_name]),
\ 'on_request': function('s:on_request', [a:server_name]),
\ })
if l:lsp_id > 0 if l:lsp_id > 0
let l:server['lsp_id'] = l:lsp_id let l:server['lsp_id'] = l:lsp_id
let l:msg = s:new_rpc_success('started lsp server successfully', { 'server_name': a:server_name, 'lsp_id': l:lsp_id }) let l:msg = s:new_rpc_success('started lsp server successfully', { 'server_name': a:server_name, 'lsp_id': l:lsp_id })

View File

@@ -183,16 +183,22 @@ function! s:on_exit(id, status, event) abort
endfunction endfunction
function! s:lsp_start(opts) abort function! s:lsp_start(opts) abort
if !has_key(a:opts, 'cmd') if has_key(a:opts, 'cmd')
let l:client_id = lsp#utils#job#start(a:opts.cmd, {
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit': function('s:on_exit'),
\ })
elseif has_key(a:opts, 'tcp')
let l:client_id = lsp#utils#job#connect(a:opts.tcp, {
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit': function('s:on_exit'),
\ })
else
return -1 return -1
endif endif
let l:client_id = lsp#utils#job#start(a:opts.cmd, {
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit': function('s:on_exit'),
\ })
let l:ctx = s:create_context(l:client_id, a:opts) let l:ctx = s:create_context(l:client_id, a:opts)
let l:ctx['id'] = l:client_id let l:ctx['id'] = l:client_id

View File

@@ -1,4 +1,4 @@
" https://github.com/prabirshrestha/async.vim#d15123af3483350e235397116b554cb37e705130 (dirty) " https://github.com/prabirshrestha/async.vim#236debf1a68d69a74f1f6647c273b0477e1ec1bf (dirty)
" :AsyncEmbed path=./autoload/lsp/utils/job.vim namespace=lsp#utils#job " :AsyncEmbed path=./autoload/lsp/utils/job.vim namespace=lsp#utils#job
" Author: Prabir Shrestha <mail at prabir dot me> " Author: Prabir Shrestha <mail at prabir dot me>
@@ -195,7 +195,11 @@ function! s:job_stop(jobid) abort
" silently for 'E900: Invalid job id' exception " silently for 'E900: Invalid job id' exception
endtry endtry
elseif l:jobinfo.type == s:job_type_vimjob elseif l:jobinfo.type == s:job_type_vimjob
call job_stop(s:jobs[a:jobid].job) if type(s:jobs[a:jobid].job) == v:t_job
call job_stop(s:jobs[a:jobid].job)
elseif type(s:jobs[a:jobid].job) == v:t_channel
call ch_close(s:jobs[a:jobid].job)
endif
endif endif
endif endif
endfunction endfunction
@@ -306,6 +310,21 @@ function! s:job_pid(jobid) abort
return 0 return 0
endfunction endfunction
function! s:callback_cb(jobid, opts, ch, data) abort
if has_key(a:opts, 'on_stdout')
call a:opts.on_stdout(a:jobid, split(a:data, "\n", 1), 'stdout')
endif
endfunction
function! s:close_cb(jobid, opts, ch) abort
if has_key(a:opts, 'on_exit')
call a:opts.on_exit(a:jobid, 'closed', 'exit')
endif
if has_key(s:jobs, a:jobid)
call remove(s:jobs, a:jobid)
endif
endfunction
" public apis {{{ " public apis {{{
function! lsp#utils#job#start(cmd, opts) abort function! lsp#utils#job#start(cmd, opts) abort
return s:job_start(a:cmd, a:opts) return s:job_start(a:cmd, a:opts)
@@ -328,6 +347,33 @@ endfunction
function! lsp#utils#job#pid(jobid) abort function! lsp#utils#job#pid(jobid) abort
return s:job_pid(a:jobid) return s:job_pid(a:jobid)
endfunction endfunction
function! lsp#utils#job#connect(addr, opts) abort
let s:jobidseq = s:jobidseq + 1
let l:jobid = s:jobidseq
let l:retry = 0
while l:retry < 5
let l:ch = ch_open(a:addr, {'waittime': 1000})
call ch_setoptions(l:ch, {
\ 'callback': function('s:callback_cb', [l:jobid, a:opts]),
\ 'close_cb': function('s:close_cb', [l:jobid, a:opts]),
\ 'mode': 'raw',
\})
if ch_status(l:ch) ==# 'open'
break
endif
sleep 100m
let l:retry += 1
endwhile
let s:jobs[l:jobid] = {
\ 'type': s:job_type_vimjob,
\ 'opts': a:opts,
\ 'job': l:ch,
\ 'channel': l:ch,
\ 'buffer': ''
\}
return l:jobid
endfunction
" }}} " }}}
let &cpo = s:save_cpo let &cpo = s:save_cpo

View File

@@ -220,15 +220,14 @@ on pyls (https://github.com/palantir/python-language-server)
augroup END augroup END
< <
TCP SERVERS *vim-lsp-tcp* TCP SERVERS *vim-lsp-tcp*
You can use netcat to connect to LSP servers that don't support stdio, but do You can use tcp to connect to LSP servers that don't support stdio. Set host
support TCP. Set your cmd to use your netcat executable (`nc` on unix-likes), and port to tcp. The Godot game engine uses 6008 as its LSP port and godot
localhost, and your server's port. The Godot game engine uses 6008 as its LSP ftplugins define gdscript or gdscript3 filetype: >
port and godot ftplugins define gdscript or gdscript3 filetype: >
au User lsp_setup au User lsp_setup
\ call lsp#register_server({ \ call lsp#register_server({
\ 'name': 'godot', \ 'name': 'godot',
\ 'cmd': ["nc", "localhost", "6008"], \ 'tcp': "localhost:6008",
\ 'allowlist': ['gdscript3', 'gdscript'] \ 'allowlist': ['gdscript3', 'gdscript']
\ }) \ })
> >