From 800c878209a7108e31be56b10b596832528638b1 Mon Sep 17 00:00:00 2001 From: Linda_pp Date: Sun, 28 Mar 2021 21:58:20 +0900 Subject: [PATCH] Support show message notification by handling `window/showMessage` response (#1120) * support window/showMessage * describe g:lsp_show_message_log_level in documentation * add tests for window/showMessage support Co-authored-by: mattn --- autoload/lsp.vim | 2 + autoload/lsp/internal/show_message.vim | 74 +++++++++++++++++++++ doc/vim-lsp.txt | 12 ++++ plugin/lsp.vim | 1 + test/lsp/internal/show_message.vimspec | 92 ++++++++++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 autoload/lsp/internal/show_message.vim create mode 100644 test/lsp/internal/show_message.vimspec diff --git a/autoload/lsp.vim b/autoload/lsp.vim index 1b78dbe4..9a84dc6b 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -63,6 +63,7 @@ function! lsp#enable() abort call lsp#internal#diagnostics#_enable() call lsp#internal#document_code_action#signs#_enable() call lsp#internal#show_message_request#_enable() + call lsp#internal#show_message#_enable() call lsp#internal#work_done_progress#_enable() call lsp#internal#completion#documentation#_enable() call s:register_events() @@ -78,6 +79,7 @@ function! lsp#disable() abort call lsp#internal#diagnostics#_disable() call lsp#internal#document_code_action#signs#_disable() call lsp#internal#show_message_request#_disable() + call lsp#internal#show_message#_disable() call lsp#internal#work_done_progress#_disable() call lsp#internal#completion#documentation#_disable() call s:unregister_events() diff --git a/autoload/lsp/internal/show_message.vim b/autoload/lsp/internal/show_message.vim new file mode 100644 index 00000000..a56bcb9f --- /dev/null +++ b/autoload/lsp/internal/show_message.vim @@ -0,0 +1,74 @@ +let s:ErrorType = 1 +let s:WarningType = 2 +let s:InfoType = 3 +let s:LogType = 4 + +function! lsp#internal#show_message#_enable() abort + if g:lsp_show_message_log_level ==# 'none' | return | endif + let s:Dispose = lsp#callbag#pipe( + \ lsp#stream(), + \ lsp#callbag#filter({x-> + \ g:lsp_show_message_log_level !=# 'none' && + \ has_key(x, 'response') && has_key(x['response'], 'method') + \ && x['response']['method'] ==# 'window/showMessage' + \ }), + \ lsp#callbag#tap({x->s:handle_show_message(x['server'], x['response']['params'])}), + \ lsp#callbag#subscribe({ 'error': function('s:on_error') }), + \ ) +endfunction + +function! lsp#internal#show_message#_disable() abort + if exists('s:Dispose') + call s:Dispose() + unlet s:Dispose + endif +endfunction + +function! s:on_error(e) abort + call lsp#log('lsp#internal#show_message error', a:e) + if exists('s:Dispose') + call s:Dispose() + unlet s:Dispose + endif +endfunction + +function! s:handle_show_message(server, params) abort + let l:level = s:name_to_level(g:lsp_show_message_log_level) + let l:type = a:params['type'] + if l:level < l:type + return + endif + + let l:message = a:params['message'] + try + if l:type == s:ErrorType + echohl ErrorMsg + elseif l:type == s:WarningType + echohl WarningMsg + endif + echom printf('%s: %s: %s', a:server, s:type_to_name(l:type), l:message) + finally + echohl None + endtry +endfunction + +function! s:name_to_level(name) abort + if a:name ==# 'none' + return 0 + elseif a:name ==# 'error' + return s:ErrorType + elseif a:name ==# 'warn' || a:name ==# 'warning' + return s:WarningType + elseif a:name ==# 'info' + return s:InfoType + elseif a:name ==# 'log' + return s:LogType + else + return 0 + endif +endfunction + +function! s:type_to_name(type) abort + return get(['unknown', 'error', 'warning', 'info', 'log'], a:type, 'unknown') +endfunction + diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index 5da9fde3..3268b4f5 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -73,6 +73,7 @@ CONTENTS *vim-lsp-contents* g:lsp_tagfunc_source_methods |g:lsp_tagfunc_source_methods| g:lsp_show_message_request_enabled |g:lsp_show_message_request_enabled| g:lsp_work_done_progress_enabled |g:lsp_work_done_progress_enabled| + g:lsp_show_message_log_level |g:lsp_show_message_log_level| Functions |vim-lsp-functions| lsp#enable |lsp#enable()| lsp#disable |lsp#disable()| @@ -913,6 +914,17 @@ g:lsp_work_done_progress_enabled *g:lsp_work_done_progress_enabled* notifications. This can be intercepted by listening to |lsp#stream()|. Set to `1` to enable. +g:lsp_show_message_log_level *g:lsp_show_message_log_level* + Type: |String| + Default: `'warning'` + + Determines log level of messages sent from LSP servers. Possible values + are one of `'none'`, `'error'`, `'warning'`, `'info'`, `'log'`. Messages + are filtered by the value set to this variable. For example, when + `'warning'` is set, `'error'` level and `'warning'` level messages are + shown but `'info'` level and `'log'` level messages are not shown. Setting + `'none'` disables to show messages completely. + ============================================================================== FUNCTIONS *vim-lsp-functions* diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 55052841..02f34c1f 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -64,6 +64,7 @@ let g:lsp_text_document_did_save_delay = get(g:, 'lsp_text_document_did_save_del let g:lsp_completion_resolve_timeout = get(g:, 'lsp_completion_resolve_timeout', 200) let g:lsp_tagfunc_source_methods = get(g:, 'lsp_tagfunc_source_methods', ['definition', 'declaration', 'implementation', 'typeDefinition']) let g:lsp_show_message_request_enabled = get(g:, 'lsp_show_message_request_enabled', 1) +let g:lsp_show_message_log_level = get(g:, 'lsp_show_message_log_level', 'warning') let g:lsp_work_done_progress_enabled = get(g:, 'lsp_work_done_progress_enabled', 0) let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')]) diff --git a/test/lsp/internal/show_message.vimspec b/test/lsp/internal/show_message.vimspec new file mode 100644 index 00000000..d2397fe6 --- /dev/null +++ b/test/lsp/internal/show_message.vimspec @@ -0,0 +1,92 @@ +let s:Error = 1 +let s:Warn = 2 +let s:Info = 3 +let s:Log = 4 + +function! s:response(type, message) abort + return { + \ 'server': 'server1', + \ 'response': { + \ 'method': 'window/showMessage', + \ 'params': { + \ 'type': a:type, + \ 'message': a:message + \ } + \ } + \ } +endfunction + +Describe lsp#internal#show_message + Before + %bwipeout! + let g:lsp_show_message_log_level = 'warning' + call lsp#internal#show_message#_disable() + call lsp#internal#show_message#_enable() + End + + After all + %bwipeout! + let g:lsp_show_message_log_level = 'none' + call lsp#internal#show_message#_disable() + End + + It should show all messages when 'log' is set to g:lsp_show_message_log_level + let g:lsp_show_message_log_level = 'log' + + redir => message_area + call lsp#stream(1, s:response(s:Error, 'error message')) + call lsp#stream(1, s:response(s:Warn, 'warn message')) + call lsp#stream(1, s:response(s:Info, 'info message')) + call lsp#stream(1, s:response(s:Log, 'log message')) + call lsp#stream(1, s:response(s:Info, 'info message2')) + call lsp#stream(1, s:response(s:Info, 'info message3')) + redir END + + Assert Match(message_area, 'server1: error: error message') + Assert Match(message_area, 'server1: warning: warn message') + Assert Match(message_area, 'server1: info: info message') + Assert Match(message_area, 'server1: log: log message') + Assert Match(message_area, 'server1: info: info message2') + Assert Match(message_area, 'server1: info: info message3') + End + + It should filter shown messages by log level set to g:lsp_show_message_log_level + let g:lsp_show_message_log_level = 'warning' + + redir => message_area + call lsp#stream(1, s:response(s:Error, 'error message')) + call lsp#stream(1, s:response(s:Warn, 'warn message')) + call lsp#stream(1, s:response(s:Info, 'info message')) + call lsp#stream(1, s:response(s:Log, 'log message')) + call lsp#stream(1, s:response(s:Info, 'info message2')) + call lsp#stream(1, s:response(s:Info, 'info message3')) + redir END + + Assert Match(message_area, 'server1: error: error message') + Assert Match(message_area, 'server1: warning: warn message') + Assert NotMatch(message_area, 'server1: info: info message') + Assert NotMatch(message_area, 'server1: log: log message') + Assert NotMatch(message_area, 'server1: info: info message2') + Assert NotMatch(message_area, 'server1: info: info message3') + End + + It should show no message when 'none' is set to g:lsp_show_message_log_level + let g:lsp_show_message_log_level = 'none' + + redir => message_area + call lsp#stream(1, s:response(s:Error, 'error message')) + call lsp#stream(1, s:response(s:Warn, 'warn message')) + call lsp#stream(1, s:response(s:Info, 'info message')) + call lsp#stream(1, s:response(s:Log, 'log message')) + call lsp#stream(1, s:response(s:Info, 'info message2')) + call lsp#stream(1, s:response(s:Info, 'info message3')) + redir END + + Assert NotMatch(message_area, 'server1: error: error message') + Assert NotMatch(message_area, 'server1: warning: warn message') + Assert NotMatch(message_area, 'server1: info: info message') + Assert NotMatch(message_area, 'server1: log: log message') + Assert NotMatch(message_area, 'server1: info: info message2') + Assert NotMatch(message_area, 'server1: info: info message3') + End +End