convert to unix lineendings

This commit is contained in:
Prabir Shrestha
2016-12-23 22:18:06 -08:00
parent cbb25285f8
commit b00348017c
3 changed files with 295 additions and 295 deletions

42
LICENSE
View File

@@ -1,21 +1,21 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 Prabir Shrestha Copyright (c) 2016 Prabir Shrestha
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

120
README.md
View File

@@ -1,60 +1,60 @@
vim-lsp (experimental) vim-lsp (experimental)
====================== ======================
Async [Language Server Protocol](https://github.com/Microsoft/language-server-protocol) plugin for vim8 and neovim. Async [Language Server Protocol](https://github.com/Microsoft/language-server-protocol) plugin for vim8 and neovim.
Internally vim-lsp uses [async.vim](https://github.com/prabirshrestha/async.vim). Internally vim-lsp uses [async.vim](https://github.com/prabirshrestha/async.vim).
Language Server Protocol VIM Client usage Language Server Protocol VIM Client usage
========================================= =========================================
Sample usage talking with `langserver-go` Sample usage talking with `langserver-go`
```vim ```vim
function! s:on_stderr(id, data, event) function! s:on_stderr(id, data, event)
echom 'lsp('.a:id.'):stderr:'.join(a:data, "\r\n") echom 'lsp('.a:id.'):stderr:'.join(a:data, "\r\n")
endfunction endfunction
function! s:on_exit(id, status, event) function! s:on_exit(id, status, event)
echom 'lsp('.a:id.'):exit:'.a:status echom 'lsp('.a:id.'):exit:'.a:status
endfunction endfunction
function! s:on_notification(id, data, event) function! s:on_notification(id, data, event)
if lsp#lspClient#is_error(a:data.response) if lsp#lspClient#is_error(a:data.response)
echom 'lsp('.a:id.'):notification:notification error receieved for '.a:data.request.method echom 'lsp('.a:id.'):notification:notification error receieved for '.a:data.request.method
elseif lsp#lspClient#is_server_instantiated_notification(a:data) elseif lsp#lspClient#is_server_instantiated_notification(a:data)
" request key will not be present in a:data " request key will not be present in a:data
" make sure to check before accessing a:data.request in order to prevent unhandled errors " make sure to check before accessing a:data.request in order to prevent unhandled errors
echom 'lsp('.a:id.'):notification:notification success receieved for '.json_encode(a:data.response) echom 'lsp('.a:id.'):notification:notification success receieved for '.json_encode(a:data.response)
else else
echom 'lsp('.a:id.'):notification:notification success receieved for '.a:data.request.method echom 'lsp('.a:id.'):notification:notification success receieved for '.a:data.request.method
endif endif
endfunction endfunction
function! s:on_notification1(id, data, event) function! s:on_notification1(id, data, event)
echom 'lsp('.a:id.'):notification1:'json_encode(a:data) echom 'lsp('.a:id.'):notification1:'json_encode(a:data)
endfunction endfunction
" go get github.com/sourcegraph/go-langserver/langserver/cmd/langserver-go " go get github.com/sourcegraph/go-langserver/langserver/cmd/langserver-go
let g:lsp_id = lsp#lspClient#start({ let g:lsp_id = lsp#lspClient#start({
\ 'cmd': ['langserver-go', '-trace', '-logfile', expand('~/Desktop/langserver-go.log')], \ 'cmd': ['langserver-go', '-trace', '-logfile', expand('~/Desktop/langserver-go.log')],
\ 'on_stderr': function('s:on_stderr'), \ 'on_stderr': function('s:on_stderr'),
\ 'on_exit': function('s:on_exit'), \ 'on_exit': function('s:on_exit'),
\ 'on_notification': function('s:on_notification') \ 'on_notification': function('s:on_notification')
\ }) \ })
if g:lsp_id > 0 if g:lsp_id > 0
echom 'lsp server running' echom 'lsp server running'
call lsp#lspClient#send(g:lsp_id, { call lsp#lspClient#send(g:lsp_id, {
\ 'method': 'initialize', \ 'method': 'initialize',
\ 'params': { \ 'params': {
\ 'capabilities': {}, \ 'capabilities': {},
\ 'rootPath': 'file:///D:/go/src/github.com/nsf/gocode' \ 'rootPath': 'file:///D:/go/src/github.com/nsf/gocode'
\ }, \ },
\ 'on_notification': function('s:on_notification1') \ 'on_notification': function('s:on_notification1')
\ }) \ })
else else
echom 'failed to start lsp server' echom 'failed to start lsp server'
endif endif
" call lsp#lspClient#stop(g:lsp_id) " call lsp#lspClient#stop(g:lsp_id)
``` ```

View File

@@ -1,214 +1,214 @@
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
let s:lsp_clients = {} " { id, opts, req_seq, on_notifications: { request, on_notification }, stdout: { max_buffer_size, buffer, content_length, headers } } let s:lsp_clients = {} " { id, opts, req_seq, on_notifications: { request, on_notification }, stdout: { max_buffer_size, buffer, content_length, headers } }
let s:lsp_default_max_buffer = -1 let s:lsp_default_max_buffer = -1
let s:lsp_text_document_sync_kind_none = 0 let s:lsp_text_document_sync_kind_none = 0
let s:lsp_text_document_sync_kind_full = 1 let s:lsp_text_document_sync_kind_full = 1
let s:lsp_text_document_sync_kind_incremental = 2 let s:lsp_text_document_sync_kind_incremental = 2
function! s:trim(str) abort function! s:trim(str) abort
return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$') return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
endfunction endfunction
function! s:_on_lsp_stdout(id, data, event) function! s:_on_lsp_stdout(id, data, event)
if has_key(s:lsp_clients, a:id) if has_key(s:lsp_clients, a:id)
let l:client = s:lsp_clients[a:id] let l:client = s:lsp_clients[a:id]
let l:client.stdout.buffer .= join(a:data, "\n") let l:client.stdout.buffer .= join(a:data, "\n")
if l:client.stdout.max_buffer_size != -1 && len(l:client.stdout.buffer) > l:client.stdout.max_buffer_size if l:client.stdout.max_buffer_size != -1 && len(l:client.stdout.buffer) > l:client.stdout.max_buffer_size
echom 'lsp: reached max buffer size' echom 'lsp: reached max buffer size'
call lsp#utils#job#stop(a:id) call lsp#utils#job#stop(a:id)
endif endif
while 1 while 1
if l:client.stdout.content_length == -1 " if content-length is -1 we haven't parsed the headers if l:client.stdout.content_length == -1 " if content-length is -1 we haven't parsed the headers
" wait for all the headers to arrive " wait for all the headers to arrive
let l:header_end_index = stridx(l:client.stdout.buffer, "\r\n\r\n") let l:header_end_index = stridx(l:client.stdout.buffer, "\r\n\r\n")
if l:header_end_index >= 0 if l:header_end_index >= 0
for l:header in split(l:client.stdout.buffer[:l:header_end_index - 1], "\r\n") for l:header in split(l:client.stdout.buffer[:l:header_end_index - 1], "\r\n")
let l:header_key_value_seperator = stridx(l:header, ":") let l:header_key_value_seperator = stridx(l:header, ":")
let l:header_key = s:trim(l:header[:l:header_key_value_seperator - 1]) let l:header_key = s:trim(l:header[:l:header_key_value_seperator - 1])
let l:header_value = s:trim(l:header[l:header_key_value_seperator + 1:]) let l:header_value = s:trim(l:header[l:header_key_value_seperator + 1:])
if l:header_key ==? 'Content-Length' if l:header_key ==? 'Content-Length'
let l:client.stdout.content_length = str2nr(l:header_value, 10) let l:client.stdout.content_length = str2nr(l:header_value, 10)
endif endif
let l:client.stdout.headers[l:header_key] = s:trim(l:header_value) let l:client.stdout.headers[l:header_key] = s:trim(l:header_value)
endfor endfor
let l:client.stdout.buffer = l:client.stdout.buffer[l:header_end_index + 4:] let l:client.stdout.buffer = l:client.stdout.buffer[l:header_end_index + 4:]
continue continue
else else
" wait for next buffer to arrive " wait for next buffer to arrive
break break
endif endif
else else
if len(l:client.stdout.buffer) >= l:client.stdout.content_length if len(l:client.stdout.buffer) >= l:client.stdout.content_length
" we have the full message " we have the full message
let l:response_str = l:client.stdout.buffer[:l:client.stdout.content_length - 1] let l:response_str = l:client.stdout.buffer[:l:client.stdout.content_length - 1]
let l:client.stdout.buffer = l:client.stdout.buffer[l:client.stdout.content_length:] let l:client.stdout.buffer = l:client.stdout.buffer[l:client.stdout.content_length:]
let l:client.stdout.content_length = -1 " reset since we are done reading the current message let l:client.stdout.content_length = -1 " reset since we are done reading the current message
let l:response_msg = json_decode(l:response_str) let l:response_msg = json_decode(l:response_str)
if has_key(l:response_msg, 'id') if has_key(l:response_msg, 'id')
let l:on_notification_data = { 'response': l:response_msg } let l:on_notification_data = { 'response': l:response_msg }
if has_key(l:client.on_notifications, l:response_msg.id) if has_key(l:client.on_notifications, l:response_msg.id)
" requests are absent for server instantiated events " requests are absent for server instantiated events
let l:on_notification_data.request = l:client.on_notifications[l:response_msg.id].request let l:on_notification_data.request = l:client.on_notifications[l:response_msg.id].request
endif endif
if has_key(l:client.opts, 'on_notification') if has_key(l:client.opts, 'on_notification')
call l:client.opts.on_notification(a:id, l:on_notification_data, 'on_notification') call l:client.opts.on_notification(a:id, l:on_notification_data, 'on_notification')
endif endif
if has_key(l:client.on_notifications, 'on_notification') if has_key(l:client.on_notifications, 'on_notification')
call l:client.on_notifications[l:response_msg.id](a:id, l:on_notification_data, 'on_notification') call l:client.on_notifications[l:response_msg.id](a:id, l:on_notification_data, 'on_notification')
endif endif
if has_key(l:client.on_notifications, l:response_msg.id) if has_key(l:client.on_notifications, l:response_msg.id)
" requests are absent for server instantiated events " requests are absent for server instantiated events
call remove(l:client.on_notifications, l:response_msg.id) call remove(l:client.on_notifications, l:response_msg.id)
endif endif
endif endif
if len(l:client.stdout.buffer) > 0 if len(l:client.stdout.buffer) > 0
" we have more data in the buffer so try parsing the new headers from top " we have more data in the buffer so try parsing the new headers from top
continue continue
else else
" we are done processing the message here so stop " we are done processing the message here so stop
break break
endif endif
else else
" we don't have the entire message body, so wait for the next buffer " we don't have the entire message body, so wait for the next buffer
break break
endif endif
endif endif
endwhile endwhile
endif endif
endfunction endfunction
function! s:_on_lsp_stderr(id, data, event) function! s:_on_lsp_stderr(id, data, event)
if has_key(s:lsp_clients, a:id) if has_key(s:lsp_clients, a:id)
let l:client = s:lsp_clients[a:id] let l:client = s:lsp_clients[a:id]
if has_key(l:client.opts, 'on_stderr') if has_key(l:client.opts, 'on_stderr')
call l:client.opts.on_stderr(a:id, a:data, a:event) call l:client.opts.on_stderr(a:id, a:data, a:event)
endif endif
endif endif
endfunction endfunction
function! s:_on_lsp_exit(id, status, event) function! s:_on_lsp_exit(id, status, event)
if has_key(s:lsp_clients, a:id) if has_key(s:lsp_clients, a:id)
let l:client = s:lsp_clients[a:id] let l:client = s:lsp_clients[a:id]
if has_key(l:client.opts, 'on_exit') if has_key(l:client.opts, 'on_exit')
call l:client.opts.on_exit(a:id, a:status, a:event) call l:client.opts.on_exit(a:id, a:status, a:event)
endif endif
endif endif
endfunction endfunction
function! s:lsp_start(opts) function! s:lsp_start(opts)
if !has_key(a:opts, 'cmd') if !has_key(a:opts, 'cmd')
return -1 return -1
endif endif
let l:lsp_client_id = lsp#utils#job#start(a:opts.cmd, { let l:lsp_client_id = lsp#utils#job#start(a:opts.cmd, {
\ 'on_stdout': function('s:_on_lsp_stdout'), \ 'on_stdout': function('s:_on_lsp_stdout'),
\ 'on_stderr': function('s:_on_lsp_stderr'), \ 'on_stderr': function('s:_on_lsp_stderr'),
\ 'on_exit': function('s:_on_lsp_exit'), \ 'on_exit': function('s:_on_lsp_exit'),
\ }) \ })
let l:max_buffer_size = s:lsp_default_max_buffer let l:max_buffer_size = s:lsp_default_max_buffer
if has_key(a:opts, 'max_buffer_size') if has_key(a:opts, 'max_buffer_size')
let l:max_buffer_size = a:opts.max_buffer_size let l:max_buffer_size = a:opts.max_buffer_size
endif endif
let s:lsp_clients[l:lsp_client_id] = { let s:lsp_clients[l:lsp_client_id] = {
\ 'id': l:lsp_client_id, \ 'id': l:lsp_client_id,
\ 'opts': a:opts, \ 'opts': a:opts,
\ 'req_seq': 0, \ 'req_seq': 0,
\ 'on_notifications': {}, \ 'on_notifications': {},
\ 'stdout': { \ 'stdout': {
\ 'max_buffer_size': l:max_buffer_size, \ 'max_buffer_size': l:max_buffer_size,
\ 'buffer': '', \ 'buffer': '',
\ 'content_length': -1, \ 'content_length': -1,
\ 'headers': {} \ 'headers': {}
\ }, \ },
\ } \ }
return l:lsp_client_id return l:lsp_client_id
endfunction endfunction
function! s:lsp_stop(id) function! s:lsp_stop(id)
call lsp#utils#job#stop(a:id) call lsp#utils#job#stop(a:id)
endfunction endfunction
function! s:lsp_send_request(id, opts) " opts = { method, params?, on_notification } function! s:lsp_send_request(id, opts) " opts = { method, params?, on_notification }
if has_key(s:lsp_clients, a:id) if has_key(s:lsp_clients, a:id)
let l:client = s:lsp_clients[a:id] let l:client = s:lsp_clients[a:id]
let l:client.req_seq = l:client.req_seq + 1 let l:client.req_seq = l:client.req_seq + 1
let l:req_seq = l:client.req_seq let l:req_seq = l:client.req_seq
let l:msg = { 'jsonrpc': '2.0', 'id': l:req_seq, 'method': a:opts.method } let l:msg = { 'jsonrpc': '2.0', 'id': l:req_seq, 'method': a:opts.method }
if has_key(a:opts, 'params') if has_key(a:opts, 'params')
let l:msg.params = a:opts.params let l:msg.params = a:opts.params
endif endif
let l:json = json_encode(l:msg) let l:json = json_encode(l:msg)
let l:req_data = 'Content-Length: ' . len(l:json) . "\r\n\r\n" . l:json let l:req_data = 'Content-Length: ' . len(l:json) . "\r\n\r\n" . l:json
let l:client.on_notifications[l:req_seq] = { 'request': l:msg } let l:client.on_notifications[l:req_seq] = { 'request': l:msg }
if has_key(a:opts, 'on_notification') if has_key(a:opts, 'on_notification')
let l:client.on_notifications[l:req_seq].on_notification = a:opts.on_notification let l:client.on_notifications[l:req_seq].on_notification = a:opts.on_notification
endif endif
call lsp#utils#job#send(l:client.id, l:req_data) call lsp#utils#job#send(l:client.id, l:req_data)
return l:req_seq return l:req_seq
else else
return -1 return -1
endif endif
endfunction endfunction
function! s:lsp_get_last_request_id(id) function! s:lsp_get_last_request_id(id)
return s:lsp_clients[a:id].req_seq return s:lsp_clients[a:id].req_seq
endfunction endfunction
function! s:lsp_is_error(notification) function! s:lsp_is_error(notification)
return has_key(a:notification, 'error') return has_key(a:notification, 'error')
endfunction endfunction
function! s:is_server_instantiated_notification(notification) function! s:is_server_instantiated_notification(notification)
return !has_key(a:notification, 'request') return !has_key(a:notification, 'request')
endfunction endfunction
" public apis {{{ " public apis {{{
let lsp#lspClient#text_document_sync_kind_none = s:lsp_text_document_sync_kind_none let lsp#lspClient#text_document_sync_kind_none = s:lsp_text_document_sync_kind_none
let lsp#lspClient#text_document_sync_kind_full = s:lsp_text_document_sync_kind_full let lsp#lspClient#text_document_sync_kind_full = s:lsp_text_document_sync_kind_full
let lsp#lspClient#text_document_sync_kind_incremental = s:lsp_text_document_sync_kind_incremental let lsp#lspClient#text_document_sync_kind_incremental = s:lsp_text_document_sync_kind_incremental
function! lsp#lspClient#start(opts) function! lsp#lspClient#start(opts)
return s:lsp_start(a:opts) return s:lsp_start(a:opts)
endfunction endfunction
function! lsp#lspClient#stop(client_id) function! lsp#lspClient#stop(client_id)
return s:lsp_stop(a:client_id) return s:lsp_stop(a:client_id)
endfunction endfunction
function! lsp#lspClient#send(client_id, opts) function! lsp#lspClient#send(client_id, opts)
return s:lsp_send_request(a:client_id, a:opts) return s:lsp_send_request(a:client_id, a:opts)
endfunction endfunction
function! lsp#lspClient#get_last_request_id(client_id) function! lsp#lspClient#get_last_request_id(client_id)
return s:lsp_get_last_request_id(a:client_id) return s:lsp_get_last_request_id(a:client_id)
endfunction endfunction
function! lsp#lspClient#is_error(notification) function! lsp#lspClient#is_error(notification)
return s:lsp_is_error(a:notification) return s:lsp_is_error(a:notification)
endfunction endfunction
function! lsp#lspClient#is_server_instantiated_notification(notification) function! lsp#lspClient#is_server_instantiated_notification(notification)
return s:is_server_instantiated_notification(a:notification) return s:is_server_instantiated_notification(a:notification)
endfunction endfunction
" }}} " }}}
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vim sw=4 ts=4 et " vim sw=4 ts=4 et