if opt.lspOptions.autoComplete && caps->has_key('completionProvider')
var triggers = caps.completionProvider.triggerCharacters
lspserver.completionTriggerChars = triggers
+ lspserver.completionLazyDoc = lspserver.caps.completionProvider->has_key('resolveProvider')
+ && lspserver.caps.completionProvider.resolveProvider
endif
# send a "initialized" notification to server
d.word = item.label
endif
d.abbr = item.label
+ d.dup = 1
if item->has_key('kind')
# namespace CompletionItemKind
# map LSP kind to complete-item-kind
d.kind = LspCompleteItemKindChar(item.kind)
endif
- if item->has_key('detail')
- d.menu = item.detail
- endif
- if item->has_key('documentation')
- if item.documentation->type() == v:t_string && item.documentation != ''
- d.info = item.documentation
- elseif item.documentation->type() == v:t_dict
- && item.documentation.value->type() == v:t_string
- d.info = item.documentation.value
+ if lspserver.completionLazyDoc
+ d.info = 'Lazy doc'
+ else
+ if item->has_key('detail')
+ d.menu = item.detail
+ endif
+ if item->has_key('documentation')
+ if item.documentation->type() == v:t_string && item.documentation != ''
+ d.info = item.documentation
+ elseif item.documentation->type() == v:t_dict
+ && item.documentation.value->type() == v:t_string
+ d.info = item.documentation.value
+ endif
endif
endif
d.user_data = item
endif
enddef
+# process the 'completionItem/resolve' reply from the LSP server
+# Result: CompletionItem
+def ProcessResolveReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
+ if reply.result->empty()
+ return
+ endif
+
+ # check if completion item is still selected
+ var cInfo = complete_info()
+ if cInfo->empty()
+ || !cInfo.pum_visible
+ || cInfo.selected == -1
+ || cInfo.items[cInfo.selected].user_data.label != reply.result.label
+ return
+ endif
+
+ var infoText: list<string>
+ var infoKind: string
+
+ if reply.result->has_key('detail')
+ infoText->extend([reply.result.detail])
+ endif
+
+ if reply.result->has_key('documentation')
+ if !infoText->empty()
+ infoText->extend(['- - -'])
+ endif
+ if reply.result.documentation->type() == v:t_dict
+ # MarkupContent
+ if reply.result.documentation.kind == 'plaintext'
+ infoText->extend(reply.result.documentation.value->split("\n"))
+ infoKind = 'text'
+ elseif reply.result.documentation.kind == 'markdown'
+ infoText->extend(reply.result.documentation.value->split("\n"))
+ infoKind = 'markdown'
+ else
+ util.ErrMsg($'Error: Unsupported documentation type ({reply.result.documentation.kind})')
+ return
+ endif
+ elseif reply.result.documentation->type() == v:t_string
+ infoText->extend(reply.result.documentation->split("\n"))
+ else
+ util.ErrMsg($'Error: Unsupported documentation ({reply.result.documentation})')
+ return
+ endif
+ endif
+
+ if infoText->empty()
+ return
+ endif
+
+ # check if completion item is changed in meantime
+ cInfo = complete_info()
+ if cInfo->empty()
+ || !cInfo.pum_visible
+ || cInfo.selected == -1
+ || cInfo.items[cInfo.selected].user_data.label != reply.result.label
+ return
+ endif
+
+ var id = popup_findinfo()
+ if id > 0
+ var bufnr = id->winbufnr()
+ infoKind->setbufvar(bufnr, '&ft')
+ if infoKind == 'markdown'
+ 3->setwinvar(id, '&cole')
+ else
+ 0->setwinvar(id, '&cole')
+ endif
+ id->popup_settext(infoText)
+ id->popup_show()
+ endif
+enddef
+
# process the 'textDocument/hover' reply from the LSP server
# Result: Hover | null
def ProcessHoverReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
'initialize': ProcessInitializeReply,
'textDocument/signatureHelp': ProcessSignaturehelpReply,
'textDocument/completion': ProcessCompletionReply,
+ 'completionItem/resolve': ProcessResolveReply,
'textDocument/hover': ProcessHoverReply,
'textDocument/documentHighlight': ProcessDocHighlightReply,
'textDocument/documentSymbol': ProcessDocSymbolReply,
# set options for insert mode completion
if opt.lspOptions.autoComplete
- setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect')
- setbufvar(bnr, '&completepopup', 'border:off')
+ if lspserver.completionLazyDoc
+ setbufvar(bnr, '&completeopt', 'menuone,popuphidden,noinsert,noselect')
+ setbufvar(bnr, '&completepopup', 'width:80,highlight:Pmenu,align:menu,border:off')
+ else
+ setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect')
+ setbufvar(bnr, '&completepopup', 'border:off')
+ endif
# <Enter> in insert mode stops completion and inserts a <Enter>
if !opt.lspOptions.noNewlineInCompletion
inoremap <expr> <buffer> <CR> pumvisible() ? "\<C-Y>\<CR>" : "\<CR>"
if opt.lspOptions.autoComplete
# Trigger 24x7 insert mode completion when text is changed
exe $'autocmd TextChangedI <buffer={bnr}> call LspComplete()'
+ if lspserver.completionLazyDoc
+ exe $'autocmd CompleteChanged <buffer={bnr}> call LspResolve()'
+ endif
endif
# Update the diagnostics when insert mode is stopped
return
enddef
+# Lazy complete documentation handler
+def g:LspResolve()
+ var lspserver: dict<any> = CurbufGetServerChecked()
+ if lspserver->empty()
+ return
+ endif
+
+ var item = v:event.completed_item
+ if item->has_key('user_data')
+ lspserver.resolveCompletion(item.user_data)
+ endif
+enddef
+
# omni complete handler
def g:LspOmniFunc(findstart: number, base: string): any
var lspserver: dict<any> = CurbufGetServerChecked()
lspserver.nextID = 1
lspserver.requests = {}
lspserver.omniCompletePending = false
+ lspserver.completionLazyDoc = false
lspserver.completionTriggerChars = []
lspserver.signaturePopup = -1
lspserver.workspaceFolders = [getcwd()]
completion: {
completionItem: {
documentationFormat: ['plaintext', 'markdown'],
+ resolveSupport: {properties: ['detail', 'documentation']},
snippetSupport: false
},
completionItemKind: {valueSet: range(1, 25)}
endif
enddef
+# Get lazy properties for a completion item.
+# Request: "completionItem/resolve"
+# Param: CompletionItem
+def ResolveCompletion(lspserver: dict<any>, item: dict<any>): void
+ # Check whether LSP server supports completion item resolve
+ if !lspserver.caps->has_key('completionProvider')
+ || !lspserver.caps.completionProvider->has_key('resolveProvider')
+ || !lspserver.caps.completionProvider.resolveProvider
+ util.ErrMsg("Error: LSP server does not support completion item resolve")
+ return
+ endif
+
+ var req = lspserver.createRequest('completionItem/resolve')
+
+ # interface CompletionItem
+ req.params = item
+
+ lspserver.sendMessage(req)
+ if exists('g:LSPTest') && g:LSPTest
+ # When running LSP tests, make this a synchronous call
+ lspserver.waitForResponse(req)
+ endif
+enddef
+
# Jump to or peek a symbol location.
#
# Send 'msg' to a LSP server and process the reply. 'msg' is one of the
textdocDidChange: function(TextdocDidChange, [lspserver]),
sendInitializedNotif: function(SendInitializedNotif, [lspserver]),
getCompletion: function(GetCompletion, [lspserver]),
+ resolveCompletion: function(ResolveCompletion, [lspserver]),
gotoDefinition: function(GotoDefinition, [lspserver]),
switchSourceHeader: function(SwitchSourceHeader, [lspserver]),
gotoDeclaration: function(GotoDeclaration, [lspserver]),