From b00348017c82ab65e5061aa7b8c59450a7d36d2d Mon Sep 17 00:00:00 2001 From: Prabir Shrestha Date: Fri, 23 Dec 2016 22:18:06 -0800 Subject: [PATCH] convert to unix lineendings --- LICENSE | 42 ++-- README.md | 120 +++++------ autoload/lsp/lspClient.vim | 428 ++++++++++++++++++------------------- 3 files changed, 295 insertions(+), 295 deletions(-) diff --git a/LICENSE b/LICENSE index 5febc5553..bf1819786 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -The MIT License (MIT) - -Copyright (c) 2016 Prabir Shrestha - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 -SOFTWARE. +The MIT License (MIT) + +Copyright (c) 2016 Prabir Shrestha + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 +SOFTWARE. diff --git a/README.md b/README.md index e4f769492..df471e6dd 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,60 @@ -vim-lsp (experimental) -====================== - -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). - -Language Server Protocol VIM Client usage -========================================= - -Sample usage talking with `langserver-go` - -```vim -function! s:on_stderr(id, data, event) - echom 'lsp('.a:id.'):stderr:'.join(a:data, "\r\n") -endfunction - -function! s:on_exit(id, status, event) - echom 'lsp('.a:id.'):exit:'.a:status -endfunction - -function! s:on_notification(id, data, event) - if lsp#lspClient#is_error(a:data.response) - echom 'lsp('.a:id.'):notification:notification error receieved for '.a:data.request.method - elseif lsp#lspClient#is_server_instantiated_notification(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 - echom 'lsp('.a:id.'):notification:notification success receieved for '.json_encode(a:data.response) - else - echom 'lsp('.a:id.'):notification:notification success receieved for '.a:data.request.method - endif -endfunction - -function! s:on_notification1(id, data, event) - echom 'lsp('.a:id.'):notification1:'json_encode(a:data) -endfunction - -" go get github.com/sourcegraph/go-langserver/langserver/cmd/langserver-go -let g:lsp_id = lsp#lspClient#start({ - \ 'cmd': ['langserver-go', '-trace', '-logfile', expand('~/Desktop/langserver-go.log')], - \ 'on_stderr': function('s:on_stderr'), - \ 'on_exit': function('s:on_exit'), - \ 'on_notification': function('s:on_notification') -\ }) - -if g:lsp_id > 0 - echom 'lsp server running' - call lsp#lspClient#send(g:lsp_id, { - \ 'method': 'initialize', - \ 'params': { - \ 'capabilities': {}, - \ 'rootPath': 'file:///D:/go/src/github.com/nsf/gocode' - \ }, - \ 'on_notification': function('s:on_notification1') - \ }) -else - echom 'failed to start lsp server' -endif - -" call lsp#lspClient#stop(g:lsp_id) -``` +vim-lsp (experimental) +====================== + +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). + +Language Server Protocol VIM Client usage +========================================= + +Sample usage talking with `langserver-go` + +```vim +function! s:on_stderr(id, data, event) + echom 'lsp('.a:id.'):stderr:'.join(a:data, "\r\n") +endfunction + +function! s:on_exit(id, status, event) + echom 'lsp('.a:id.'):exit:'.a:status +endfunction + +function! s:on_notification(id, data, event) + if lsp#lspClient#is_error(a:data.response) + echom 'lsp('.a:id.'):notification:notification error receieved for '.a:data.request.method + elseif lsp#lspClient#is_server_instantiated_notification(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 + echom 'lsp('.a:id.'):notification:notification success receieved for '.json_encode(a:data.response) + else + echom 'lsp('.a:id.'):notification:notification success receieved for '.a:data.request.method + endif +endfunction + +function! s:on_notification1(id, data, event) + echom 'lsp('.a:id.'):notification1:'json_encode(a:data) +endfunction + +" go get github.com/sourcegraph/go-langserver/langserver/cmd/langserver-go +let g:lsp_id = lsp#lspClient#start({ + \ 'cmd': ['langserver-go', '-trace', '-logfile', expand('~/Desktop/langserver-go.log')], + \ 'on_stderr': function('s:on_stderr'), + \ 'on_exit': function('s:on_exit'), + \ 'on_notification': function('s:on_notification') +\ }) + +if g:lsp_id > 0 + echom 'lsp server running' + call lsp#lspClient#send(g:lsp_id, { + \ 'method': 'initialize', + \ 'params': { + \ 'capabilities': {}, + \ 'rootPath': 'file:///D:/go/src/github.com/nsf/gocode' + \ }, + \ 'on_notification': function('s:on_notification1') + \ }) +else + echom 'failed to start lsp server' +endif + +" call lsp#lspClient#stop(g:lsp_id) +``` diff --git a/autoload/lsp/lspClient.vim b/autoload/lsp/lspClient.vim index e60f98afc..6ed56429c 100644 --- a/autoload/lsp/lspClient.vim +++ b/autoload/lsp/lspClient.vim @@ -1,214 +1,214 @@ -let s:save_cpo = &cpo -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_default_max_buffer = -1 - -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_incremental = 2 - -function! s:trim(str) abort - return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$') -endfunction - -function! s:_on_lsp_stdout(id, data, event) - if has_key(s:lsp_clients, a:id) - let l:client = s:lsp_clients[a:id] - - 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 - echom 'lsp: reached max buffer size' - call lsp#utils#job#stop(a:id) - endif - - while 1 - 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 - let l:header_end_index = stridx(l:client.stdout.buffer, "\r\n\r\n") - if l:header_end_index >= 0 - 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 = 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' - let l:client.stdout.content_length = str2nr(l:header_value, 10) - endif - let l:client.stdout.headers[l:header_key] = s:trim(l:header_value) - endfor - let l:client.stdout.buffer = l:client.stdout.buffer[l:header_end_index + 4:] - continue - else - " wait for next buffer to arrive - break - endif - else - if len(l:client.stdout.buffer) >= l:client.stdout.content_length - " we have the full message - 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.content_length = -1 " reset since we are done reading the current message - let l:response_msg = json_decode(l:response_str) - if has_key(l:response_msg, 'id') - let l:on_notification_data = { 'response': l:response_msg } - if has_key(l:client.on_notifications, l:response_msg.id) - " requests are absent for server instantiated events - let l:on_notification_data.request = l:client.on_notifications[l:response_msg.id].request - endif - if has_key(l:client.opts, 'on_notification') - call l:client.opts.on_notification(a:id, l:on_notification_data, 'on_notification') - endif - 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') - endif - if has_key(l:client.on_notifications, l:response_msg.id) - " requests are absent for server instantiated events - call remove(l:client.on_notifications, l:response_msg.id) - endif - endif - if len(l:client.stdout.buffer) > 0 - " we have more data in the buffer so try parsing the new headers from top - continue - else - " we are done processing the message here so stop - break - endif - else - " we don't have the entire message body, so wait for the next buffer - break - endif - endif - endwhile - endif -endfunction - -function! s:_on_lsp_stderr(id, data, event) - if has_key(s:lsp_clients, a:id) - let l:client = s:lsp_clients[a:id] - if has_key(l:client.opts, 'on_stderr') - call l:client.opts.on_stderr(a:id, a:data, a:event) - endif - endif -endfunction - -function! s:_on_lsp_exit(id, status, event) - if has_key(s:lsp_clients, a:id) - let l:client = s:lsp_clients[a:id] - if has_key(l:client.opts, 'on_exit') - call l:client.opts.on_exit(a:id, a:status, a:event) - endif - endif -endfunction - -function! s:lsp_start(opts) - if !has_key(a:opts, 'cmd') - return -1 - endif - - let l:lsp_client_id = lsp#utils#job#start(a:opts.cmd, { - \ 'on_stdout': function('s:_on_lsp_stdout'), - \ 'on_stderr': function('s:_on_lsp_stderr'), - \ 'on_exit': function('s:_on_lsp_exit'), - \ }) - - let l:max_buffer_size = s:lsp_default_max_buffer - if has_key(a:opts, 'max_buffer_size') - let l:max_buffer_size = a:opts.max_buffer_size - endif - - let s:lsp_clients[l:lsp_client_id] = { - \ 'id': l:lsp_client_id, - \ 'opts': a:opts, - \ 'req_seq': 0, - \ 'on_notifications': {}, - \ 'stdout': { - \ 'max_buffer_size': l:max_buffer_size, - \ 'buffer': '', - \ 'content_length': -1, - \ 'headers': {} - \ }, - \ } - - return l:lsp_client_id -endfunction - -function! s:lsp_stop(id) - call lsp#utils#job#stop(a:id) -endfunction - -function! s:lsp_send_request(id, opts) " opts = { method, params?, on_notification } - if has_key(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:req_seq = l:client.req_seq - - let l:msg = { 'jsonrpc': '2.0', 'id': l:req_seq, 'method': a:opts.method } - if has_key(a:opts, 'params') - let l:msg.params = a:opts.params - endif - - let l:json = json_encode(l:msg) - 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 } - if has_key(a:opts, 'on_notification') - let l:client.on_notifications[l:req_seq].on_notification = a:opts.on_notification - endif - - call lsp#utils#job#send(l:client.id, l:req_data) - - return l:req_seq - else - return -1 - endif -endfunction - -function! s:lsp_get_last_request_id(id) - return s:lsp_clients[a:id].req_seq -endfunction - -function! s:lsp_is_error(notification) - return has_key(a:notification, 'error') -endfunction - -function! s:is_server_instantiated_notification(notification) - return !has_key(a:notification, 'request') -endfunction - -" public apis {{{ - -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_incremental = s:lsp_text_document_sync_kind_incremental - -function! lsp#lspClient#start(opts) - return s:lsp_start(a:opts) -endfunction - -function! lsp#lspClient#stop(client_id) - return s:lsp_stop(a:client_id) -endfunction - -function! lsp#lspClient#send(client_id, opts) - return s:lsp_send_request(a:client_id, a:opts) -endfunction - -function! lsp#lspClient#get_last_request_id(client_id) - return s:lsp_get_last_request_id(a:client_id) -endfunction - -function! lsp#lspClient#is_error(notification) - return s:lsp_is_error(a:notification) -endfunction - -function! lsp#lspClient#is_server_instantiated_notification(notification) - return s:is_server_instantiated_notification(a:notification) -endfunction - -" }}} - -let &cpo = s:save_cpo -unlet s:save_cpo -" vim sw=4 ts=4 et +let s:save_cpo = &cpo +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_default_max_buffer = -1 + +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_incremental = 2 + +function! s:trim(str) abort + return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$') +endfunction + +function! s:_on_lsp_stdout(id, data, event) + if has_key(s:lsp_clients, a:id) + let l:client = s:lsp_clients[a:id] + + 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 + echom 'lsp: reached max buffer size' + call lsp#utils#job#stop(a:id) + endif + + while 1 + 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 + let l:header_end_index = stridx(l:client.stdout.buffer, "\r\n\r\n") + if l:header_end_index >= 0 + 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 = 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' + let l:client.stdout.content_length = str2nr(l:header_value, 10) + endif + let l:client.stdout.headers[l:header_key] = s:trim(l:header_value) + endfor + let l:client.stdout.buffer = l:client.stdout.buffer[l:header_end_index + 4:] + continue + else + " wait for next buffer to arrive + break + endif + else + if len(l:client.stdout.buffer) >= l:client.stdout.content_length + " we have the full message + 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.content_length = -1 " reset since we are done reading the current message + let l:response_msg = json_decode(l:response_str) + if has_key(l:response_msg, 'id') + let l:on_notification_data = { 'response': l:response_msg } + if has_key(l:client.on_notifications, l:response_msg.id) + " requests are absent for server instantiated events + let l:on_notification_data.request = l:client.on_notifications[l:response_msg.id].request + endif + if has_key(l:client.opts, 'on_notification') + call l:client.opts.on_notification(a:id, l:on_notification_data, 'on_notification') + endif + 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') + endif + if has_key(l:client.on_notifications, l:response_msg.id) + " requests are absent for server instantiated events + call remove(l:client.on_notifications, l:response_msg.id) + endif + endif + if len(l:client.stdout.buffer) > 0 + " we have more data in the buffer so try parsing the new headers from top + continue + else + " we are done processing the message here so stop + break + endif + else + " we don't have the entire message body, so wait for the next buffer + break + endif + endif + endwhile + endif +endfunction + +function! s:_on_lsp_stderr(id, data, event) + if has_key(s:lsp_clients, a:id) + let l:client = s:lsp_clients[a:id] + if has_key(l:client.opts, 'on_stderr') + call l:client.opts.on_stderr(a:id, a:data, a:event) + endif + endif +endfunction + +function! s:_on_lsp_exit(id, status, event) + if has_key(s:lsp_clients, a:id) + let l:client = s:lsp_clients[a:id] + if has_key(l:client.opts, 'on_exit') + call l:client.opts.on_exit(a:id, a:status, a:event) + endif + endif +endfunction + +function! s:lsp_start(opts) + if !has_key(a:opts, 'cmd') + return -1 + endif + + let l:lsp_client_id = lsp#utils#job#start(a:opts.cmd, { + \ 'on_stdout': function('s:_on_lsp_stdout'), + \ 'on_stderr': function('s:_on_lsp_stderr'), + \ 'on_exit': function('s:_on_lsp_exit'), + \ }) + + let l:max_buffer_size = s:lsp_default_max_buffer + if has_key(a:opts, 'max_buffer_size') + let l:max_buffer_size = a:opts.max_buffer_size + endif + + let s:lsp_clients[l:lsp_client_id] = { + \ 'id': l:lsp_client_id, + \ 'opts': a:opts, + \ 'req_seq': 0, + \ 'on_notifications': {}, + \ 'stdout': { + \ 'max_buffer_size': l:max_buffer_size, + \ 'buffer': '', + \ 'content_length': -1, + \ 'headers': {} + \ }, + \ } + + return l:lsp_client_id +endfunction + +function! s:lsp_stop(id) + call lsp#utils#job#stop(a:id) +endfunction + +function! s:lsp_send_request(id, opts) " opts = { method, params?, on_notification } + if has_key(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:req_seq = l:client.req_seq + + let l:msg = { 'jsonrpc': '2.0', 'id': l:req_seq, 'method': a:opts.method } + if has_key(a:opts, 'params') + let l:msg.params = a:opts.params + endif + + let l:json = json_encode(l:msg) + 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 } + if has_key(a:opts, 'on_notification') + let l:client.on_notifications[l:req_seq].on_notification = a:opts.on_notification + endif + + call lsp#utils#job#send(l:client.id, l:req_data) + + return l:req_seq + else + return -1 + endif +endfunction + +function! s:lsp_get_last_request_id(id) + return s:lsp_clients[a:id].req_seq +endfunction + +function! s:lsp_is_error(notification) + return has_key(a:notification, 'error') +endfunction + +function! s:is_server_instantiated_notification(notification) + return !has_key(a:notification, 'request') +endfunction + +" public apis {{{ + +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_incremental = s:lsp_text_document_sync_kind_incremental + +function! lsp#lspClient#start(opts) + return s:lsp_start(a:opts) +endfunction + +function! lsp#lspClient#stop(client_id) + return s:lsp_stop(a:client_id) +endfunction + +function! lsp#lspClient#send(client_id, opts) + return s:lsp_send_request(a:client_id, a:opts) +endfunction + +function! lsp#lspClient#get_last_request_id(client_id) + return s:lsp_get_last_request_id(a:client_id) +endfunction + +function! lsp#lspClient#is_error(notification) + return s:lsp_is_error(a:notification) +endfunction + +function! lsp#lspClient#is_server_instantiated_notification(notification) + return s:is_server_instantiated_notification(a:notification) +endfunction + +" }}} + +let &cpo = s:save_cpo +unlet s:save_cpo +" vim sw=4 ts=4 et