mirror of
https://github.com/prabirshrestha/vim-lsp.git
synced 2025-12-14 20:35:59 +01:00
Add tcp feature (#985)
* Add tcp feature * Update doc * Update async.vim embed * Update doc
This commit is contained in:
@@ -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 })
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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']
|
||||||
\ })
|
\ })
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user