--- /dev/null
+" vint: -ProhibitUnusedVariable
+let s:debounce_timer_id = 0
+
+function! s:not_supported(what) abort
+ return lsp#utils#error(a:what.' not supported for '.&filetype)
+endfunction
+
+function! lsp#ui#vim#signature_help#get_signature_help_under_cursor() abort
+ let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_signature_help_provider(v:val)')
+
+ if len(l:servers) == 0
+ call s:not_supported('Retrieving signature help')
+ return
+ endif
+
+ let l:position = lsp#get_position()
+ for l:server in l:servers
+ call lsp#send_request(l:server, {
+ \ 'method': 'textDocument/signatureHelp',
+ \ 'params': {
+ \ 'textDocument': lsp#get_text_document_identifier(),
+ \ 'position': l:position,
+ \ },
+ \ 'on_notification': function('s:handle_signature_help', [l:server]),
+ \ })
+ endfor
+
+ call lsp#log('Retrieving signature help')
+ return
+endfunction
+
+function! s:handle_signature_help(server, data) abort
+ if lsp#client#is_error(a:data['response'])
+ call lsp#utils#error('Failed to retrieve signature help information for ' . a:server)
+ return
+ endif
+
+ if !has_key(a:data['response'], 'result')
+ return
+ endif
+
+ if !empty(a:data['response']['result']) && !empty(a:data['response']['result']['signatures'])
+ " Get current signature.
+ let l:signatures = get(a:data['response']['result'], 'signatures', [])
+ let l:signature_index = get(a:data['response']['result'], 'activeSignature', 0)
+ let l:signature = get(l:signatures, l:signature_index, {})
+ if empty(l:signature)
+ return
+ endif
+
+ " Signature label.
+ let l:label = l:signature['label']
+
+ " Mark current parameter.
+ if has_key(a:data['response']['result'], 'activeParameter')
+ let l:parameters = get(l:signature, 'parameters', [])
+ let l:parameter_index = a:data['response']['result']['activeParameter']
+ let l:parameter = get(l:parameters, l:parameter_index, {})
+ let l:parameter_label = s:get_parameter_label(l:signature, l:parameter)
+ if !empty(l:parameter_label)
+ let l:label = substitute(l:label, '\V\(' . escape(l:parameter_label, '\/?') . '\)', '`\1`', 'g')
+ endif
+ endif
+
+ let l:contents = [l:label]
+
+ if exists('l:parameter')
+ let l:parameter_doc = s:get_parameter_doc(l:parameter)
+ if !empty(l:parameter_doc)
+ call add(l:contents, '')
+ call add(l:contents, l:parameter_doc)
+ call add(l:contents, '')
+ endif
+ endif
+
+ if has_key(l:signature, 'documentation')
+ call add(l:contents, l:signature['documentation'])
+ endif
+
+ call lsp#ui#vim#output#preview(a:server, l:contents, {'statusline': ' LSP SignatureHelp'})
+ return
+ else
+ " signature help is used while inserting. So this must be graceful.
+ "call lsp#utils#error('No signature help information found')
+ endif
+endfunction
+
+function! s:get_parameter_label(signature, parameter) abort
+ if has_key(a:parameter, 'label')
+ if type(a:parameter['label']) == type([])
+ let l:string_range = a:parameter['label']
+ return strcharpart(
+ \ a:signature['label'],
+ \ l:string_range[0],
+ \ l:string_range[1] - l:string_range[0])
+ endif
+ return a:parameter['label']
+ endif
+ return ''
+endfunction
+
+function! s:get_parameter_doc(parameter) abort
+ if !has_key(a:parameter, 'documentation')
+ return ''
+ endif
+
+ let l:doc = copy(a:parameter['documentation'])
+ if type(l:doc) == type({})
+ let l:doc['value'] = printf('***%s*** - %s', a:parameter['label'], l:doc['value'])
+ return l:doc
+ endif
+ return printf('***%s*** - %s', a:parameter['label'], l:doc)
+endfunction
+
+function! s:on_cursor_moved() abort
+ let l:bufnr = bufnr('%')
+ call timer_stop(s:debounce_timer_id)
+ if g:lsp_signature_help_enabled
+ let s:debounce_timer_id = timer_start(g:lsp_signature_help_delay, function('s:on_text_changed_after', [l:bufnr]), { 'repeat': 1 })
+ endif
+endfunction
+
+function! s:on_text_changed_after(bufnr, timer) abort
+ if bufnr('%') != a:bufnr
+ return
+ endif
+ if index(['i', 's'], mode()[0]) == -1
+ return
+ endif
+ if win_id2win(lsp#ui#vim#output#getpreviewwinid()) >= 1
+ return
+ endif
+
+ " Cache trigger chars since this loop is heavy
+ let l:chars = get(b:, 'lsp_signature_help_trigger_character', [])
+ if empty(l:chars)
+ for l:server_name in lsp#get_allowed_servers(a:bufnr)
+ let l:chars += lsp#capabilities#get_signature_help_trigger_characters(l:server_name)
+ endfor
+ let b:lsp_signature_help_trigger_character = l:chars
+ endif
+
+ if index(l:chars, lsp#utils#_get_before_char_skip_white()) >= 0
+ call lsp#ui#vim#signature_help#get_signature_help_under_cursor()
+ endif
+endfunction
+
+function! lsp#ui#vim#signature_help#setup() abort
+ augroup _lsp_signature_help_
+ autocmd!
+ autocmd CursorMoved,CursorMovedI * call s:on_cursor_moved()
+ augroup END
+endfunction
+
+function! lsp#ui#vim#signature_help#_disable() abort
+ augroup _lsp_signature_help_
+ autocmd!
+ augroup END
+endfunction
+