Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions autoload/lsp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,9 @@ function! lsp#default_get_supported_capabilities(server_info) abort
\ },
\ 'textDocument': {
\ 'completion': {
\ 'completionItem': {
\ 'documentationFormat': ['plaintext']
\ },
\ 'completionItemKind': {
\ 'valueSet': lsp#omni#get_completion_item_kinds()
\ }
Expand Down Expand Up @@ -696,6 +699,8 @@ function! s:handle_initialize(server_name, data) abort
call lsp#ui#vim#signature_help#setup()
endif

call lsp#ui#vim#documentation#setup()

doautocmd User lsp_server_init
endfunction

Expand Down
6 changes: 5 additions & 1 deletion autoload/lsp/omni.vim
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,12 @@ function! lsp#omni#default_get_vim_completion_item(item, ...) abort
endif

if has_key(a:item, 'documentation')
if type(a:item['documentation']) == type('')
if type(a:item['documentation']) == type('') " field is string
let l:completion['info'] .= a:item['documentation']
elseif type(a:item['documentation']) == type({}) &&
\ has_key(a:item['documentation'], 'value')
" field is MarkupContent (hopefully 'plaintext')
let l:completion['info'] .= a:item['documentation']['value']
endif
endif

Expand Down
75 changes: 75 additions & 0 deletions autoload/lsp/ui/vim/documentation.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
let s:use_vim_popup = has('patch-8.1.1517') && !has('nvim')
let s:use_nvim_float = exists('*nvim_open_win') && has('nvim')

let s:last_popup_id = -1

function! s:complete_done() abort
" Use a timer to avoid textlock (see :h textlock).
let l:event = deepcopy(v:event)
call timer_start(0, {-> s:show_documentation(l:event)})
endfunction

function! s:show_documentation(event) abort
call s:close_popup()

if !has_key(a:event['completed_item'], 'info') || empty(a:event['completed_item']['info'])
return
endif

let l:right = wincol() < winwidth(0) / 2

" TODO: Neovim
if l:right
let l:line = a:event['row'] + 1
let l:col = a:event['col'] + a:event['width'] + 1 + (a:event['scrollbar'] ? 1 : 0)
else
let l:line = a:event['row'] + 1
let l:col = a:event['col'] - 1
endif

" TODO: Support markdown
let l:data = split(a:event['completed_item']['info'], '\n')
let l:lines = []
let l:syntax_lines = []
let l:ft = lsp#ui#vim#output#append(l:data, l:lines, l:syntax_lines)

let l:current_win_id = win_getid()

if s:use_vim_popup
let s:last_popup_id = popup_create('(no documentation available)', {'line': l:line, 'col': l:col, 'pos': l:right ? 'topleft' : 'topright', 'padding': [0, 1, 0, 1]})
elseif s:use_nvim_float
let l:height = winheight(0) - l:line + 1
let l:width = l:right ? winwidth(0) - l:col + 1 : l:col
let s:last_popup_id = lsp#ui#vim#output#floatingpreview([])
call nvim_win_set_config(s:last_popup_id, {'relative': 'win', 'anchor': l:right ? 'NW' : 'NE', 'row': l:line - 1, 'col': l:col - 1, 'height': l:height, 'width': l:width})
endif

call setbufvar(winbufnr(s:last_popup_id), 'lsp_syntax_highlights', l:syntax_lines)
call setbufvar(winbufnr(s:last_popup_id), 'lsp_do_conceal', 1)
call lsp#ui#vim#output#setcontent(s:last_popup_id, l:lines, l:ft)
let [l:bufferlines, l:maxwidth] = lsp#ui#vim#output#get_size_info(getline(1, '$'))

call win_gotoid(l:current_win_id)

if s:use_nvim_float
call lsp#ui#vim#output#adjust_float_placement(l:bufferlines, l:maxwidth)
call nvim_win_set_config(s:last_popup_id, {'relative': 'win', 'row': l:line - 1, 'col': l:col - 1})
endif
endfunction

function! s:close_popup() abort
if s:last_popup_id >= 0
if s:use_vim_popup | call popup_close(s:last_popup_id) | endif
if s:use_nvim_float | call nvim_win_close(s:last_popup_id, 1) | endif

let s:last_popup_id = -1
endif
endfunction

function! lsp#ui#vim#documentation#setup() abort
augroup lsp_documentation_popup
autocmd!
autocmd CompleteChanged * call s:complete_done()
autocmd CompleteDone * call s:close_popup()
augroup end
endfunction
82 changes: 46 additions & 36 deletions autoload/lsp/ui/vim/output.vim
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,8 @@ function! lsp#ui#vim#output#floatingpreview(data) abort
endif

let l:opts = s:get_float_positioning(l:height, l:width)

let s:winid = nvim_open_win(buf, v:true, l:opts)
call nvim_win_set_option(s:winid, 'winhl', 'Normal:Pmenu,NormalNC:Pmenu')
call nvim_win_set_option(s:winid, 'foldenable', v:false)
call nvim_win_set_option(s:winid, 'wrap', v:true)
call nvim_win_set_option(s:winid, 'statusline', '')
call nvim_win_set_option(s:winid, 'number', v:false)
call nvim_win_set_option(s:winid, 'relativenumber', v:false)
call nvim_win_set_option(s:winid, 'cursorline', v:false)
let l:opts['style'] = 'minimal'
let s:winid = nvim_open_win(buf, v:false, l:opts)
" Enable closing the preview with esc, but map only in the scratch buffer
nmap <buffer><silent> <esc> :pclose<cr>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we're not focusing the float, this would apply to the main buffer, I believe.

Copy link
Contributor Author

@clason clason Sep 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're right. Didn't notice that. How weird...

But even without that line, I get strange styling of the main buffer whenever a float is open (color changes in the status bar).

elseif s:use_vim_popup
Expand All @@ -143,31 +136,42 @@ function! lsp#ui#vim#output#floatingpreview(data) abort
return s:winid
endfunction

function! s:setcontent(lines, ft) abort
if s:use_vim_popup
" vim popup
call setbufline(winbufnr(s:winid), 1, a:lines)
function! lsp#ui#vim#output#setcontent(winid, lines, ft) abort
if s:use_vim_popup || s:use_nvim_float
let l:buf = winbufnr(a:winid)
call setbufline(l:buf, 1, a:lines)
let l:lightline_toggle = v:false
if exists('#lightline') && !has('nvim')
" Lightline does not work in popups but does not recognize it yet.
" It is ugly to have an check for an other plugin here, better fix lightline...
let l:lightline_toggle = v:true
call lightline#disable()
endif
call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover')

let l:filetype = a:ft . '.lsp-hover'
if s:use_vim_popup
call win_execute(a:winid, 'setlocal filetype=' . l:filetype)
elseif s:use_nvim_float
let l:height = len(a:lines)
let l:width = max(map(a:lines, 'strdisplaywidth(v:val)'))
let l:opts = s:get_float_positioning(l:height, l:width)
call nvim_win_set_config(a:winid, l:opts)
call nvim_buf_set_option(l:buf, 'filetype', l:filetype)
endif

if l:lightline_toggle
call lightline#enable()
endif
else
" nvim floating or preview
" preview
call setline(1, a:lines)

setlocal readonly nomodifiable
silent! let &l:filetype = a:ft . '.lsp-hover'
endif
endfunction

function! s:adjust_float_placement(bufferlines, maxwidth) abort
function! lsp#ui#vim#output#adjust_float_placement(bufferlines, maxwidth) abort
if s:use_nvim_float
let l:win_config = {}
let l:height = min([winheight(s:winid), a:bufferlines])
Expand Down Expand Up @@ -284,6 +288,26 @@ function! s:align_preview(options) abort
endif
endfunction

function! lsp#ui#vim#output#get_size_info(lines) abort
" Get size information while still having the buffer active
let l:maxwidth = max(map(a:lines, 'strdisplaywidth(v:val)'))
if g:lsp_preview_max_width > 0
let l:bufferlines = 0
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])

" Determine, for each line, how many "virtual" lines it spans, and add
" these together for all lines in the buffer
for l:line in a:lines
let l:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
let l:bufferlines += max([l:num_lines, 1])
endfor
else
let l:bufferlines = line('$')
endif

return [l:bufferlines, l:maxwidth]
endfunction

function! lsp#ui#vim#output#preview(server, data, options) abort
if s:winid && type(s:preview_data) == type(a:data)
\ && s:preview_data == a:data
Expand All @@ -303,7 +327,7 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
let s:preview_data = a:data
let l:lines = []
let l:syntax_lines = []
let l:ft = s:append(a:data, l:lines, l:syntax_lines)
let l:ft = lsp#ui#vim#output#append(a:data, l:lines, l:syntax_lines)

if has_key(a:options, 'filetype')
let l:ft = a:options['filetype']
Expand All @@ -318,23 +342,9 @@ function! lsp#ui#vim#output#preview(server, data, options) abort

call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines)
call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal)
call s:setcontent(l:lines, l:ft)

" Get size information while still having the buffer active
let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)'))
if g:lsp_preview_max_width > 0
let l:bufferlines = 0
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])
call lsp#ui#vim#output#setcontent(s:winid, l:lines, l:ft)

" Determine, for each line, how many "virtual" lines it spans, and add
" these together for all lines in the buffer
for l:line in getline(1, '$')
let l:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
let l:bufferlines += max([l:num_lines, 1])
endfor
else
let l:bufferlines = line('$')
endif
let [l:bufferlines, l:maxwidth] = lsp#ui#vim#output#get_size_info(getline(1, '$'))

if s:use_preview
" Set statusline
Expand All @@ -353,7 +363,7 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
if s:winid && (s:use_vim_popup || s:use_nvim_float)
if s:use_nvim_float
" Neovim floats
call s:adjust_float_placement(l:bufferlines, l:maxwidth)
call lsp#ui#vim#output#adjust_float_placement(l:bufferlines, l:maxwidth)
call s:set_cursor(l:current_window_id, a:options)
call s:add_float_closing_hooks()
elseif s:use_vim_popup
Expand All @@ -371,10 +381,10 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
return ''
endfunction

function! s:append(data, lines, syntax_lines) abort
function! lsp#ui#vim#output#append(data, lines, syntax_lines) abort
if type(a:data) == type([])
for l:entry in a:data
call s:append(entry, a:lines, a:syntax_lines)
call lsp#ui#vim#output#append(entry, a:lines, a:syntax_lines)
endfor

return 'markdown'
Expand Down