var lsp_log_dir: string = '/tmp/'
 
 # process the 'initialize' method reply from the LSP server
-def lsp#processInitializeReply(ftype: string, reply: dict<any>): void
+def LSPprocessInitializeReply(ftype: string, reply: dict<any>): void
   if reply.result->len() <= 0
     return
   endif
       exe 'inoremap <buffer> <silent> ' .. ch .. ' ' .. ch .. "<C-R>=lsp#showSignature()<CR>"
     endfor
   endif
+
+  # send a "initialized" notification to server
+  lsp#send_initialized(ftype)
 enddef
 
 # process the 'textDocument/definition' / 'textDocument/declaration' method
 # replies from the LSP server
-def lsp#processDefDeclReply(reply: dict<any>): void
+def LSPprocessDefDeclReply(reply: dict<any>): void
   if reply.result->len() == 0
     echomsg "Error: definition is not found"
     return
 enddef
 
 # process the 'textDocument/signatureHelp' reply from the LSP server
-def lsp#processSignaturehelpReply(reply: dict<any>): void
+def LSPprocessSignaturehelpReply(reply: dict<any>): void
   var result: dict<any> = reply.result
   if result.signatures->len() <= 0
     echomsg 'No signature help available'
 enddef
 
 # process the 'textDocument/completion' reply from the LSP server
-def lsp#processCompletionReply(ftype: string, reply: dict<any>): void
+def LSPprocessCompletionReply(ftype: string, reply: dict<any>): void
   var items: list<dict<any>> = reply.result.items
 
   for item in items
   lsp_servers[ftype].completePending = v:false
 enddef
 
+# process the 'textDocument/hover' reply from the LSP server
+def LSPprocessHoverReply(ftype: string, reply: dict<any>): void
+  if type(reply.result) == v:t_none
+    return
+  endif
+
+  if reply.result.contents.kind == 'plaintext'
+    reply.result.contents.value->split("\n")->popup_atcursor({'moved': 'word'})
+  else
+    echomsg 'Error: Unsupported hover contents type (' .. reply.result.contents.kind .. ')'
+  endif
+enddef
+
 # Process varous reply messages from the LSP server
 def lsp#process_reply(ftype: string, req: dict<any>, reply: dict<any>): void
   if req.method == 'initialize'
-    lsp#processInitializeReply(ftype, reply)
+    LSPprocessInitializeReply(ftype, reply)
   elseif req.method == 'textDocument/definition' || req.method == 'textDocument/declaration'
-    lsp#processDefDeclReply(reply)
+    LSPprocessDefDeclReply(reply)
   elseif req.method == 'textDocument/signatureHelp'
-    lsp#processSignaturehelpReply(reply)
+    LSPprocessSignaturehelpReply(reply)
   elseif req.method == 'textDocument/completion'
-    lsp#processCompletionReply(ftype, reply)
+    LSPprocessCompletionReply(ftype, reply)
+  elseif req.method == 'textDocument/hover'
+    LSPprocessHoverReply(ftype, reply)
   else
     echomsg "Error: Unsupported reply received from LSP server: " .. string(reply)
   endif
 enddef
 
 # Send a request message to LSP server
-def lsp#sendto_server(ftype: string, content: dict<any>): void
+def LSPsendto_server(ftype: string, content: dict<any>): void
   var req_js: string = content->json_encode()
   var msg = "Content-Length: " .. req_js->len() .. "\r\n\r\n"
   var ch = lsp_servers[ftype].job->job_getchannel()
   var initparams: dict<any> = {}
   initparams.processId = getpid()
   initparams.clientInfo = {'name': 'Vim', 'version': string(v:versionlong)}
-  initparams.capabilities = {}
   req.params->extend(initparams)
 
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
   return 1
 enddef
 
+# Send a "initialized" LSP notification
+def lsp#send_initialized(ftype: string)
+  var notif: dict<any> = lsp#create_notifmsg(ftype, 'initialized')
+  LSPsendto_server(ftype, notif)
+enddef
+
 # Start a LSP server
 def lsp#start_server(ftype: string): number
   if lsp_servers[ftype].running
 # Send a 'shutdown' request to the LSP server
 def lsp#shutdown_server(ftype: string): void
   var req = lsp#create_reqmsg(ftype, 'shutdown')
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
 enddef
 
 # Send a 'exit' notification to the LSP server
 def lsp#exit_server(ftype: string): void
-  var req: dict<any> = lsp#create_notifmsg(ftype, 'exit')
-  lsp#sendto_server(ftype, req)
+  var notif: dict<any> = lsp#create_notifmsg(ftype, 'exit')
+  LSPsendto_server(ftype, notif)
 enddef
 
 # Stop a LSP server
   tdi.text = getbufline(bnum, 1, '$')->join("\n") .. "\n"
   notif.params->extend({'textDocument': tdi})
 
-  lsp#sendto_server(ftype, notif)
+  LSPsendto_server(ftype, notif)
 enddef
 
 # Send a LSP "textDocument/didClose" notification
   tdid.uri = 'file://' .. fname
   notif.params->extend({'textDocument': tdid})
 
-  lsp#sendto_server(ftype, notif)
+  LSPsendto_server(ftype, notif)
 enddef
 
 # Goto a definition using "textDocument/definition" LSP request
   # interface Position
   req.params->extend({'position': {'line': lnum, 'character': col}})
 
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
 enddef
 
 # Goto a declaration using "textDocument/declaration" LSP request
   #     interface Position
   req.params->extend({'position': {'line': lnum, 'character': col}})
 
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
 enddef
 
 # Show the signature using "textDocument/signatureHelp" LSP method
   # first send all the changes in the current buffer to the LSP server
   listener_flush()
 
-  var fname: string = expand('%:p')
   var ftype: string = &filetype
-  var lnum: number = line('.') - 1
-  var col: number = col('.') - 1
-
-  if fname == '' || ftype == ''
+  if ftype == ''
     return ''
   endif
+
   if !lsp_servers->has_key(ftype)
     echomsg 'Error: LSP server for "' .. ftype .. '" filetype is not found'
     return ''
     return ''
   endif
 
+  var fname: string = expand('%:p')
+  if fname == ''
+    return ''
+  endif
+
+  var lnum: number = line('.') - 1
+  var col: number = col('.') - 1
+
   var req = lsp#create_reqmsg(ftype, 'textDocument/signatureHelp')
   # interface SignatureHelpParams
   #   interface TextDocumentPositionParams
   #     interface Position
   req.params->extend({'position': {'line': lnum, 'character': col}})
 
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
   return ''
 enddef
 
   changeset->add({'text': getbufline(bnum, 1, '$')->join("\n") .. "\n"})
   notif.params->extend({'contentChanges': changeset})
 
-  lsp#sendto_server(ftype, notif)
+  LSPsendto_server(ftype, notif)
 enddef
 
 # A new buffer is opened. If LSP is supported for this buffer, then add it
   endif
   lsp#textdoc_didopen(bnum, ftype)
 
+  # Display hover information
+  autocmd CursorHold <buffer> call LSPhover()
+
   # add a listener to track changes to this buffer
   listener_add(function('lsp#bufchange_listener'), bnum)
   setbufvar(bnum, '&completefunc', 'lsp#completeFunc')
   cwindow
 enddef
 
-def lsp#getCompletion(): void
-  var fname = expand('%:p')
+def LSPgetCompletion(): void
   var ftype = &filetype
-  var lnum = line('.') - 1
-  var col = col('.') - 1
-  if fname == '' || ftype == ''
+  if ftype == ''
     return
   endif
   if !lsp_servers->has_key(ftype)
     return
   endif
 
+  var fname = expand('%:p')
+  if fname == ''
+    return
+  endif
+
+  var lnum = line('.') - 1
+  var col = col('.') - 1
+
   var req = lsp#create_reqmsg(ftype, 'textDocument/completion')
 
   # interface CompletionParams
   # interface Position
   req.params->extend({'position': {'line': lnum, 'character': col}})
 
-  lsp#sendto_server(ftype, req)
+  LSPsendto_server(ftype, req)
 enddef
 
 def lsp#completeFunc(findstart: number, base: string): any
     lsp_servers[ftype].completePending = v:true
     lsp_servers[ftype].completeItems = []
     # initiate a request to LSP server to get list of completions
-    lsp#getCompletion()
+    LSPgetCompletion()
 
     # locate the start of the word
     var line = getline('.')
   endif
 enddef
 
+def LSPhover()
+  var ftype = &filetype
+  if ftype == ''
+    return
+  endif
+
+  if !lsp_servers->has_key(ftype)
+    echomsg 'Error: LSP server for "' .. ftype .. '" filetype is not found'
+    return
+  endif
+  if !lsp_servers[ftype].running
+    echomsg 'Error: LSP server for "' .. ftype .. '" filetype is not running'
+    return
+  endif
+
+  var fname = expand('%:p')
+  if fname == ''
+    return
+  endif
+  var lnum = line('.') - 1
+  var col = col('.') - 1
+
+  var req = lsp#create_reqmsg(ftype, 'textDocument/hover')
+  # interface HoverParams
+  # interface TextDocumentPositionParams
+  # interface TextDocumentIdentifier
+  req.params->extend({'textDocument': {'uri': 'file://' .. fname}})
+  # interface Position
+  req.params->extend({'position': {'line': lnum, 'character': col}})
+
+  LSPsendto_server(ftype, req)
+enddef
+
 # vim: shiftwidth=2 sts=2 expandtab