5 # The functions called by plugin/lsp.vim are in this file.
7 # Needs Vim 9.0 and higher
12 import './options.vim' as opt
13 import './lspserver.vim' as lserver
15 import './buffer.vim' as buf
16 import './completion.vim'
17 import './textedit.vim'
20 import './outline.vim'
21 import './signature.vim'
22 import './codeaction.vim'
23 import './inlayhints.vim'
25 # LSP server information
26 var LSPServers: list<dict<any>> = []
28 # filetype to LSP server map
29 var ftypeServerMap: dict<list<dict<any>>> = {}
31 var lspInitializedOnce = false
34 hlset([{name: 'LspTextRef', default: true, linksto: 'Search'}])
35 hlset([{name: 'LspReadRef', default: true, linksto: 'DiffChange'}])
36 hlset([{name: 'LspWriteRef', default: true, linksto: 'DiffDelete'}])
38 var override = &cursorline
39 && &cursorlineopt =~ '\<line\>\|\<screenline\>\|\<both\>'
41 prop_type_add('LspTextRef', {highlight: 'LspTextRef', override: override})
42 prop_type_add('LspReadRef', {highlight: 'LspReadRef', override: override})
43 prop_type_add('LspWriteRef', {highlight: 'LspWriteRef', override: override})
49 :set ballooneval balloonevalterm
50 lspInitializedOnce = true
53 # Returns the LSP servers for the a specific filetype. Based on how well there
54 # score, LSP servers with the same score are being returned.
55 # Returns an empty list if the servers is not found.
56 def LspGetServers(bnr: number, ftype: string): list<dict<any>>
57 if !ftypeServerMap->has_key(ftype)
61 var bufDir = bnr->bufname()->fnamemodify(':p:h')
63 return ftypeServerMap[ftype]->filter((key, lspserver) => {
64 # Don't run the server if no path is found
65 if !lspserver.runIfSearchFiles->empty()
66 var path = util.FindNearestRootDir(bufDir, lspserver.runIfSearchFiles)
73 # Don't run the server if a path is found
74 if !lspserver.runUnlessSearchFiles->empty()
75 var path = util.FindNearestRootDir(bufDir, lspserver.runUnlessSearchFiles)
87 # Add a LSP server for a filetype
88 def LspAddServer(ftype: string, lspsrv: dict<any>)
89 var lspsrvlst = ftypeServerMap->has_key(ftype) ? ftypeServerMap[ftype] : []
90 lspsrvlst->add(lspsrv)
91 ftypeServerMap[ftype] = lspsrvlst
94 # Enable/disable the logging of the language server protocol messages
95 def ServerDebug(arg: string)
96 if ['errors', 'messages', 'off', 'on']->index(arg) == -1
97 util.ErrMsg($'Unsupported argument "{arg}"')
101 var lspservers: list<dict<any>> = buf.CurbufGetServers()
102 if lspservers->empty()
103 util.WarnMsg($'No Lsp servers found for "{@%}"')
107 for lspserver in lspservers
109 util.ClearTraceLogs(lspserver.logfile)
110 util.ClearTraceLogs(lspserver.errfile)
111 lspserver.debug = true
113 lspserver.debug = false
114 elseif arg == 'messages'
115 util.ServerMessagesShow(lspserver.logfile)
117 util.ServerMessagesShow(lspserver.errfile)
122 # Show information about all the LSP servers
123 export def ShowAllServers()
125 # Add filetype to server mapping information
126 lines->add('Filetype Information')
127 lines->add('====================')
128 for [ftype, lspservers] in ftypeServerMap->items()
129 for lspserver in lspservers
130 lines->add($"Filetype: '{ftype}'")
131 lines->add($"Server Name: '{lspserver.name}'")
132 lines->add($"Server Path: '{lspserver.path}'")
133 lines->add($"Status: {lspserver.running ? 'Running' : 'Not running'}")
138 # Add buffer to server mapping information
139 lines->add('Buffer Information')
140 lines->add('==================')
141 for bnr in range(1, bufnr('$'))
142 var lspservers: list<dict<any>> = buf.BufLspServersGet(bnr)
143 if !lspservers->empty()
144 lines->add($"Buffer: '{bufname(bnr)}'")
145 for lspserver in lspservers
146 lines->add($"Server Path: '{lspserver.path}'")
147 lines->add($"Status: {lspserver.running ? 'Running' : 'Not running'}")
153 var wid = bufwinid('Language-Servers')
159 :new Language-Servers
160 :setlocal buftype=nofile
161 :setlocal bufhidden=wipe
163 :setlocal nonumber nornu
164 :setlocal fdc=0 signcolumn=no
168 :setlocal nomodifiable
171 # Create a new window containing the buffer "bname" or if the window is
172 # already present then jump to it.
173 def OpenScratchWindow(bname: string)
174 var wid = bufwinid(bname)
181 :setlocal buftype=nofile
182 :setlocal bufhidden=wipe
184 :setlocal nonumber nornu
185 :setlocal fdc=0 signcolumn=no
189 # Show the status of the LSP server for the current buffer
190 def ShowServer(arg: string)
191 if ['status', 'capabilities', 'initializeRequest', 'messages']->index(arg) == -1
192 util.ErrMsg($'Unsupported argument "{arg}"')
196 var lspservers: list<dict<any>> = buf.CurbufGetServers()
197 if lspservers->empty()
198 util.WarnMsg($'No Lsp servers found for "{@%}"')
202 var windowName: string = ''
203 var lines: list<string> = []
204 if arg->empty() || arg == 'status'
205 windowName = $'LangServer-Status'
206 for lspserver in lspservers
208 lines->extend(['', repeat('=', &columns), ''])
210 var msg = $"LSP server '{lspserver.name}' is "
214 msg ..= 'not running'
218 elseif arg == 'capabilities'
219 windowName = $'LangServer-Capabilities'
220 for lspserver in lspservers
222 lines->extend(['', repeat('=', &columns), ''])
224 lines->extend(lspserver.getCapabilities())
226 elseif arg == 'initializeRequest'
227 windowName = $'LangServer-InitializeRequest'
228 for lspserver in lspservers
230 lines->extend(['', repeat('=', &columns), ''])
232 lines->extend(lspserver.getInitializeRequest())
234 elseif arg == 'messages'
235 windowName = $'LangServer-Messages'
236 for lspserver in lspservers
238 lines->extend(['', repeat('=', &columns), ''])
240 lines->extend(lspserver.getMessages())
243 util.ErrMsg($'Unsupported argument "{arg}"')
248 OpenScratchWindow(windowName)
251 :setlocal nomodifiable
253 util.InfoMsg(lines[0])
257 # Get LSP server running status for filetype "ftype"
258 # Return true if running, or false if not found or not running
259 export def ServerRunning(ftype: string): bool
260 if ftypeServerMap->has_key(ftype)
261 var lspservers = ftypeServerMap[ftype]
262 for lspserver in lspservers
272 # Go to a definition using "textDocument/definition" LSP request
273 export def GotoDefinition(peek: bool, cmdmods: string, count: number)
274 var lspserver: dict<any> = buf.CurbufGetServerChecked('definition')
275 if lspserver->empty()
279 lspserver.gotoDefinition(peek, cmdmods, count)
282 # Go to a declaration using "textDocument/declaration" LSP request
283 export def GotoDeclaration(peek: bool, cmdmods: string, count: number)
284 var lspserver: dict<any> = buf.CurbufGetServerChecked('declaration')
285 if lspserver->empty()
289 lspserver.gotoDeclaration(peek, cmdmods, count)
292 # Go to a type definition using "textDocument/typeDefinition" LSP request
293 export def GotoTypedef(peek: bool, cmdmods: string, count: number)
294 var lspserver: dict<any> = buf.CurbufGetServerChecked('typeDefinition')
295 if lspserver->empty()
299 lspserver.gotoTypeDef(peek, cmdmods, count)
302 # Go to a implementation using "textDocument/implementation" LSP request
303 export def GotoImplementation(peek: bool, cmdmods: string, count: number)
304 var lspserver: dict<any> = buf.CurbufGetServerChecked('implementation')
305 if lspserver->empty()
309 lspserver.gotoImplementation(peek, cmdmods, count)
312 # Switch source header using "textDocument/switchSourceHeader" LSP request
313 # (Clangd specifc extension)
314 export def SwitchSourceHeader()
315 var lspserver: dict<any> = buf.CurbufGetServerChecked()
316 if lspserver->empty()
320 lspserver.switchSourceHeader()
323 # Show the signature using "textDocument/signatureHelp" LSP method
324 # Invoked from an insert-mode mapping, so return an empty string.
325 def g:LspShowSignature(): string
326 var lspserver: dict<any> = buf.CurbufGetServerChecked()
327 if lspserver->empty()
331 # first send all the changes in the current buffer to the LSP server
333 lspserver.showSignature()
337 # A buffer is saved. Send the "textDocument/didSave" LSP notification
339 var bnr: number = expand('<abuf>')->str2nr()
340 var lspservers: list<dict<any>> = buf.BufLspServersGet(bnr)->filter(
341 (key, lspsrv) => !lspsrv->empty() && lspsrv.running
344 if lspservers->empty()
348 for lspserver in lspservers
349 lspserver.didSaveFile(bnr)
353 # Return the diagnostic text from the LSP server for the current mouse line to
354 # display in a balloon
355 var lspDiagPopupID: number = 0
356 var lspDiagPopupInfo: dict<any> = {}
357 def g:LspDiagExpr(): any
358 # Display the diagnostic message only if the mouse is over the gutter for
360 if opt.lspOptions.noDiagHoverOnLine && v:beval_col >= 2
364 var diagsInfo: list<dict<any>> = diag.GetDiagsByLine(
368 if diagsInfo->empty()
369 # No diagnostic for the current cursor location
373 # Include all diagnostics from the current line in the message
374 var message: list<string> = []
375 for diag in diagsInfo
376 message->extend(diag.message->split("\n"))
382 # Called after leaving insert mode. Used to process diag messages (if any)
383 def LspLeftInsertMode()
384 if !exists('b:LspDiagsUpdatePending')
387 :unlet b:LspDiagsUpdatePending
389 var bnr: number = bufnr()
390 diag.ProcessNewDiags(bnr)
393 # Add buffer-local autocmds when attaching a LSP server to a buffer
394 def AddBufLocalAutocmds(lspserver: dict<any>, bnr: number): void
395 var acmds: list<dict<any>> = []
397 # file saved notification handler
398 acmds->add({bufnr: bnr,
399 event: 'BufWritePost',
400 group: 'LSPBufferAutocmds',
401 cmd: 'LspSavedFile()'})
403 # Update the diagnostics when insert mode is stopped
404 acmds->add({bufnr: bnr,
405 event: 'InsertLeave',
406 group: 'LSPBufferAutocmds',
407 cmd: 'LspLeftInsertMode()'})
409 # Auto highlight all the occurrences of the current keyword
410 if opt.lspOptions.autoHighlight &&
411 lspserver.isDocumentHighlightProvider
412 acmds->add({bufnr: bnr,
413 event: 'CursorMoved',
414 group: 'LSPBufferAutocmds',
415 cmd: 'call LspDocHighlightClear() | call LspDocHighlight("silent")'})
418 # Show diagnostics on the status line
419 if opt.lspOptions.showDiagOnStatusLine
420 acmds->add({bufnr: bnr,
421 event: 'CursorMoved',
422 group: 'LSPBufferAutocmds',
423 cmd: 'LspShowCurrentDiagInStatusLine()'})
429 def BufferInit(lspserverId: number, bnr: number): void
430 var lspserver = buf.BufLspServerGetById(bnr, lspserverId)
431 if lspserver->empty() || !lspserver.running
435 var ftype: string = bnr->getbufvar('&filetype')
436 lspserver.textdocDidOpen(bnr, ftype)
438 # add a listener to track changes to this buffer
439 listener_add((_bnr: number, start: number, end: number, added: number, changes: list<dict<number>>) => {
440 lspserver.textdocDidChange(bnr, start, end, added, changes)
443 AddBufLocalAutocmds(lspserver, bnr)
445 setbufvar(bnr, '&balloonexpr', 'g:LspDiagExpr()')
447 signature.BufferInit(lspserver)
448 inlayhints.BufferInit(lspserver, bnr)
450 var allServersReady = true
451 var lspservers: list<dict<any>> = buf.BufLspServersGet(bnr)
452 for lspsrv in lspservers
454 allServersReady = false
460 for lspsrv in lspservers
461 # It's only possible to initialize completion when all server capabilities
463 var completionServer = buf.BufLspServerGet(bnr, 'completion')
464 if !completionServer->empty() && lspsrv.id == completionServer.id
465 completion.BufferInit(lspsrv, bnr, ftype)
469 if exists('#User#LspAttached')
470 doautocmd <nomodeline> User LspAttached
475 # A new buffer is opened. If LSP is supported for this buffer, then add it
476 export def AddFile(bnr: number): void
477 if buf.BufHasLspServer(bnr)
478 # LSP server for this buffer is already initialized and running
483 if util.LspUriRemote(bnr->bufname()->fnamemodify(':p'))
487 var ftype: string = bnr->getbufvar('&filetype')
491 var lspservers: list<dict<any>> = LspGetServers(bnr, ftype)
492 if lspservers->empty()
495 for lspserver in lspservers
496 if !lspserver.running
497 if !lspInitializedOnce
500 lspserver.startServer(bnr)
502 buf.BufLspServerSet(bnr, lspserver)
505 BufferInit(lspserver.id, bnr)
507 augroup LSPBufferAutocmds
508 exe $'autocmd User LspServerReady_{lspserver.id} ++once BufferInit({lspserver.id}, {bnr})'
514 # Notify LSP server to remove a file
515 export def RemoveFile(bnr: number): void
516 var lspservers: list<dict<any>> = buf.BufLspServersGet(bnr)
517 for lspserver in lspservers->copy()
518 if lspserver->empty()
522 lspserver.textdocDidClose(bnr)
524 diag.DiagRemoveFile(bnr)
525 buf.BufLspServerRemove(bnr, lspserver)
529 # Stop all the LSP servers
530 export def StopAllServers()
531 for lspserver in LSPServers
533 lspserver.stopServer()
538 # Add all the buffers with 'filetype' set to "ftype" to the language server.
539 def AddBuffersToLsp(ftype: string)
540 # Add all the buffers with the same file type as the current buffer
541 for binfo in getbufinfo({bufloaded: 1})
542 if binfo.bufnr->getbufvar('&filetype') == ftype
548 # Restart the LSP server for the current buffer
550 var lspservers: list<dict<any>> = buf.CurbufGetServers()
551 if lspservers->empty()
552 util.WarnMsg($'No Lsp servers found for "{@%}"')
556 # Remove all the buffers with the same file type as the current buffer
557 var ftype: string = &filetype
558 for binfo in getbufinfo()
559 if binfo.bufnr->getbufvar('&filetype') == ftype
560 RemoveFile(binfo.bufnr)
564 for lspserver in lspservers
565 # Stop the server (if running)
567 lspserver.stopServer()
570 # Start the server again
571 lspserver.startServer(bufnr(''))
574 AddBuffersToLsp(ftype)
577 # Add the LSP server for files with 'filetype' as "ftype".
578 def AddServerForFiltype(lspserver: dict<any>, ftype: string, omnicompl: bool)
579 LspAddServer(ftype, lspserver)
580 completion.OmniComplSet(ftype, omnicompl)
582 # If a buffer of this file type is already present, then send it to the LSP
584 AddBuffersToLsp(ftype)
587 # Register a LSP server for one or more file types
588 export def AddServer(serverList: list<dict<any>>)
589 for server in serverList
590 if !server->has_key('filetype') || !server->has_key('path')
591 util.ErrMsg('LSP server information is missing filetype or path')
594 # Enable omni-completion by default
595 server.omnicompl = get(server, 'omnicompl', v:true)
597 if !server.path->executable()
598 if !opt.lspOptions.ignoreMissingServer
599 util.ErrMsg($'LSP server {server.path} is not found')
603 if server->has_key('args')
604 if server.args->type() != v:t_list
605 util.ErrMsg($'Arguments for LSP server {server.args} is not a List')
612 if !server->has_key('initializationOptions')
613 || server.initializationOptions->type() != v:t_dict
614 server.initializationOptions = {}
617 if !server->has_key('forceOffsetEncoding')
618 || server.forceOffsetEncoding->type() != v:t_string
619 || (server.forceOffsetEncoding != 'utf-8'
620 && server.forceOffsetEncoding != 'utf-16'
621 && server.forceOffsetEncoding != 'utf-32')
622 server.forceOffsetEncoding = ''
625 if !server->has_key('customNotificationHandlers')
626 || server.customNotificationHandlers->type() != v:t_dict
627 server.customNotificationHandlers = {}
630 if server->has_key('processDiagHandler')
631 if server.processDiagHandler->type() != v:t_func
632 util.ErrMsg($'Setting of processDiagHandler {server.processDiagHandler} is not a Funcref nor lambda')
636 server.processDiagHandler = null_function
639 if !server->has_key('customRequestHandlers')
640 || server.customRequestHandlers->type() != v:t_dict
641 server.customRequestHandlers = {}
644 if !server->has_key('features') || server.features->type() != v:t_dict
648 if server.omnicompl->type() != v:t_bool
649 util.ErrMsg($'Setting of omnicompl {server.omnicompl} is not a Boolean')
653 if !server->has_key('syncInit')
654 server.syncInit = v:false
657 if !server->has_key('name') || server.name->type() != v:t_string
658 || server.name->empty()
659 # Use the executable name (without the extension) as the language server
661 server.name = server.path->fnamemodify(':t:r')
664 if !server->has_key('debug') || server.debug->type() != v:t_bool
668 if !server->has_key('traceLevel')
669 || server->type() != v:t_string
670 || (server.traceLevel != 'off' && server.traceLevel != 'debug'
671 && server.traceLevel != 'verbose')
672 server.traceLevel = 'off'
675 if !server->has_key('workspaceConfig')
676 || server.workspaceConfig->type() != v:t_dict
677 server.workspaceConfig = {}
680 if !server->has_key('rootSearch') || server.rootSearch->type() != v:t_list
681 server.rootSearch = []
684 if !server->has_key('runIfSearch') ||
685 server.runIfSearch->type() != v:t_list
686 server.runIfSearch = []
689 if !server->has_key('runUnlessSearch') ||
690 server.runUnlessSearch->type() != v:t_list
691 server.runUnlessSearch = []
694 var lspserver: dict<any> = lserver.NewLspServer(server)
696 var ftypes = server.filetype
697 if ftypes->type() == v:t_string
698 AddServerForFiltype(lspserver, ftypes, server.omnicompl)
699 elseif ftypes->type() == v:t_list
701 AddServerForFiltype(lspserver, ftype, server.omnicompl)
704 util.ErrMsg($'Unsupported file type information "{ftypes->string()}" in LSP server registration')
710 # The LSP server is considered ready when the server capabilities are
711 # received ("initialize" LSP reply message)
712 export def ServerReady(): bool
713 var fname: string = @%
718 var lspservers: list<dict<any>> = buf.CurbufGetServers()
719 if lspservers->empty()
723 for lspserver in lspservers
732 # set the LSP server trace level for the current buffer
733 # Params: SetTraceParams
734 def ServerTraceSet(traceVal: string)
735 if ['off', 'messages', 'verbose']->index(traceVal) == -1
736 util.ErrMsg($'Unsupported argument "{traceVal}"')
740 var lspservers: list<dict<any>> = buf.CurbufGetServers()
741 if lspservers->empty()
742 util.WarnMsg($'No Lsp servers found for "{@%}"')
746 for lspserver in lspservers
747 lspserver.setTrace(traceVal)
751 # Display the diagnostic messages from the LSP server for the current buffer
753 export def ShowDiagnostics(): void
757 # Show the diagnostic message for the current line
758 export def LspShowCurrentDiag(atPos: bool)
759 diag.ShowCurrentDiag(atPos)
762 # Display the diagnostics for the current line in the status line.
763 export def LspShowCurrentDiagInStatusLine()
764 var fname: string = @%
769 diag.ShowCurrentDiagInStatusLine()
772 # get the count of diagnostics in the current buffer
773 export def ErrorCount(): dict<number>
774 var res = {Error: 0, Warn: 0, Info: 0, Hint: 0}
775 var fname: string = @%
780 return diag.DiagsGetErrorCount()
783 # jump to the next/previous/first diagnostic message in the current buffer
784 export def JumpToDiag(which: string, count: number = 0): void
785 diag.LspDiagsJump(which, count)
788 # Display the hover message from the LSP server for the current cursor
790 export def Hover(cmdmods: string)
791 var lspserver: dict<any> = buf.CurbufGetServerChecked('hover')
792 if lspserver->empty()
796 lspserver.hover(cmdmods)
799 # show symbol references
800 export def ShowReferences(peek: bool)
801 var lspserver: dict<any> = buf.CurbufGetServerChecked('references')
802 if lspserver->empty()
806 lspserver.showReferences(peek)
809 # highlight all the places where a symbol is referenced
810 def g:LspDocHighlight(cmdmods: string = '')
811 var lspserver: dict<any> = buf.CurbufGetServerChecked('documentHighlight')
812 if lspserver->empty()
816 lspserver.docHighlight(cmdmods)
819 # clear the symbol reference highlight
820 def g:LspDocHighlightClear()
821 var lspserver: dict<any> = buf.CurbufGetServerChecked('documentHighlight')
822 if lspserver->empty()
826 if has('patch-9.0.0233')
827 prop_remove({types: ['LspTextRef', 'LspReadRef', 'LspWriteRef'], all: true})
829 prop_remove({type: 'LspTextRef', all: true})
830 prop_remove({type: 'LspReadRef', all: true})
831 prop_remove({type: 'LspWriteRef', all: true})
835 def g:LspRequestDocSymbols()
836 if outline.SkipOutlineRefresh()
840 var fname: string = @%
845 var lspserver: dict<any> = buf.CurbufGetServer()
846 if lspserver->empty() || !lspserver.running || !lspserver.ready
850 lspserver.getDocSymbols(fname)
853 # open a window and display all the symbols in a file (outline)
854 export def Outline(cmdmods: string, winsize: number)
855 outline.OpenOutlineWindow(cmdmods, winsize)
856 g:LspRequestDocSymbols()
859 # Format the entire file
860 export def TextDocFormat(range_args: number, line1: number, line2: number)
862 util.ErrMsg('Current file is not a modifiable file')
866 var lspserver: dict<any> = buf.CurbufGetServerChecked('documentFormatting')
867 if lspserver->empty()
871 var fname: string = @%
873 lspserver.textDocFormat(fname, true, line1, line2)
875 lspserver.textDocFormat(fname, false, 0, 0)
879 # TODO: Add support for textDocument.onTypeFormatting?
880 # Will this slow down Vim?
882 # Display all the locations where the current symbol is called from.
883 # Uses LSP "callHierarchy/incomingCalls" request
884 export def IncomingCalls()
885 var lspserver: dict<any> = buf.CurbufGetServerChecked()
886 if lspserver->empty()
890 lspserver.incomingCalls(@%)
893 # Display all the symbols used by the current symbol.
894 # Uses LSP "callHierarchy/outgoingCalls" request
895 export def OutgoingCalls()
896 var lspserver: dict<any> = buf.CurbufGetServerChecked()
897 if lspserver->empty()
901 lspserver.outgoingCalls(@%)
904 # Display the type hierarchy for the current symbol. Direction is 0 for
905 # sub types and 1 for super types.
906 export def TypeHierarchy(direction: number)
907 var lspserver: dict<any> = buf.CurbufGetServerChecked()
908 if lspserver->empty()
912 lspserver.typeHierarchy(direction)
916 # Uses LSP "textDocument/rename" request
917 export def Rename(a_newName: string)
918 var lspserver: dict<any> = buf.CurbufGetServerChecked('rename')
919 if lspserver->empty()
923 var newName: string = a_newName
925 var sym: string = expand('<cword>')
926 newName = input($"Rename symbol '{sym}' to: ", sym)
931 # clear the input prompt
935 lspserver.renameSymbol(newName)
938 # Perform a code action
939 # Uses LSP "textDocument/codeAction" request
940 export def CodeAction(line1: number, line2: number, query: string)
941 var lspserver: dict<any> = buf.CurbufGetServerChecked('codeAction')
942 if lspserver->empty()
946 var fname: string = @%
947 lspserver.codeAction(fname, line1, line2, query)
951 # Uses LSP "textDocument/codeLens" request
952 export def CodeLens()
953 var lspserver: dict<any> = buf.CurbufGetServerChecked('codeLens')
954 if lspserver->empty()
958 lspserver.codeLens(@%)
961 # Perform a workspace wide symbol lookup
962 # Uses LSP "workspace/symbol" request
963 export def SymbolSearch(queryArg: string, cmdmods: string)
964 var lspserver: dict<any> = buf.CurbufGetServerChecked()
965 if lspserver->empty()
969 var query: string = queryArg
971 query = input('Lookup symbol: ', expand('<cword>'))
978 lspserver.workspaceQuery(query, true, cmdmods)
981 # Display the list of workspace folders
982 export def ListWorkspaceFolders()
983 var lspservers: list<dict<any>> = buf.CurbufGetServers()
984 for lspserver in lspservers
985 util.InfoMsg($'Workspace Folders: "{lspserver.name}" {lspserver.workspaceFolders->string()}')
989 # Add a workspace folder. Default is to use the current folder.
990 export def AddWorkspaceFolder(dirArg: string)
991 var dirName: string = dirArg
993 dirName = input('Add Workspace Folder: ', getcwd(), 'dir')
999 if !dirName->isdirectory()
1000 util.ErrMsg($'{dirName} is not a directory')
1004 var lspservers: list<dict<any>> = buf.CurbufGetServers()
1006 for lspserver in lspservers
1007 lspserver.addWorkspaceFolder(dirName)
1011 # Remove a workspace folder. Default is to use the current folder.
1012 export def RemoveWorkspaceFolder(dirArg: string)
1013 var dirName: string = dirArg
1015 dirName = input('Remove Workspace Folder: ', getcwd(), 'dir')
1021 if !dirName->isdirectory()
1022 util.ErrMsg($'{dirName} is not a directory')
1026 var lspservers: list<dict<any>> = buf.CurbufGetServers()
1027 for lspserver in lspservers
1028 lspserver.removeWorkspaceFolder(dirName)
1032 # expand the previous selection or start a new selection
1033 export def SelectionExpand()
1034 var lspserver: dict<any> = buf.CurbufGetServerChecked('selectionRange')
1035 if lspserver->empty()
1039 lspserver.selectionExpand()
1042 # shrink the previous selection or start a new selection
1043 export def SelectionShrink()
1044 var lspserver: dict<any> = buf.CurbufGetServerChecked('selectionRange')
1045 if lspserver->empty()
1049 lspserver.selectionShrink()
1052 # fold the entire document
1053 export def FoldDocument()
1054 var lspserver: dict<any> = buf.CurbufGetServerChecked('foldingRange')
1055 if lspserver->empty()
1059 if &foldmethod != 'manual'
1060 util.ErrMsg("Only works when 'foldmethod' is 'manual'")
1064 var fname: string = @%
1065 lspserver.foldRange(fname)
1068 # Enable diagnostic highlighting for all the buffers
1069 export def DiagHighlightEnable()
1070 diag.DiagsHighlightEnable()
1073 # Disable diagnostic highlighting for all the buffers
1074 export def DiagHighlightDisable()
1075 diag.DiagsHighlightDisable()
1078 # Function to use with the 'tagfunc' option.
1079 export def TagFunc(pat: string, flags: string, info: dict<any>): any
1080 var lspserver: dict<any> = buf.CurbufGetServerChecked('definition')
1081 if lspserver->empty()
1085 return lspserver.tagFunc(pat, flags, info)
1088 # Function to use with the 'formatexpr' option.
1089 export def FormatExpr(): number
1090 var lspserver: dict<any> = buf.CurbufGetServerChecked('documentFormatting')
1091 if lspserver->empty()
1095 lspserver.textDocFormat(@%, true, v:lnum, v:lnum + v:count - 1)
1099 export def RegisterCmdHandler(cmd: string, Handler: func)
1100 codeaction.RegisterCmdHandler(cmd, Handler)
1103 # Command-line completion for the ":LspServer <cmd>" sub command
1104 def LspServerSubCmdComplete(cmds: list<string>, arglead: string, cmdline: string, cursorPos: number): list<string>
1105 var wordBegin = cmdline->match('\s\+\zs\S', cursorPos)
1110 # Make sure there are no additional sub-commands
1111 var wordEnd = cmdline->stridx(' ', wordBegin)
1113 return cmds->filter((_, val) => val =~ $'^{arglead}')
1119 # Command-line completion for the ":LspServer debug" command
1120 def LspServerDebugComplete(arglead: string, cmdline: string, cursorPos: number): list<string>
1121 return LspServerSubCmdComplete(['errors', 'messages', 'off', 'on'],
1122 arglead, cmdline, cursorPos)
1125 # Command-line completion for the ":LspServer show" command
1126 def LspServerShowComplete(arglead: string, cmdline: string, cursorPos: number): list<string>
1127 return LspServerSubCmdComplete(['capabilities', 'initializeRequest',
1128 'messages', 'status'], arglead, cmdline,
1132 # Command-line completion for the ":LspServer trace" command
1133 def LspServerTraceComplete(arglead: string, cmdline: string, cursorPos: number): list<string>
1134 return LspServerSubCmdComplete(['messages', 'off', 'verbose'],
1135 arglead, cmdline, cursorPos)
1138 # Command-line completion for the ":LspServer" command
1139 export def LspServerComplete(arglead: string, cmdline: string, cursorPos: number): list<string>
1142 var l = ['debug', 'restart', 'show', 'trace']
1144 # Skip the command name
1145 var i = cmdline->stridx(' ', 0)
1146 wordBegin = cmdline->match('\s\+\zs\S', i)
1151 wordEnd = cmdline->stridx(' ', wordBegin)
1153 return filter(l, (_, val) => val =~ $'^{arglead}')
1156 var cmd = cmdline->strpart(wordBegin, wordEnd - wordBegin)
1158 return LspServerDebugComplete(arglead, cmdline, wordEnd)
1159 elseif cmd == 'restart'
1160 elseif cmd == 'show'
1161 return LspServerShowComplete(arglead, cmdline, wordEnd)
1162 elseif cmd == 'trace'
1163 return LspServerTraceComplete(arglead, cmdline, wordEnd)
1169 # ":LspServer" command handler
1170 export def LspServerCmd(args: string)
1171 if args->stridx('debug') == 0
1173 var subcmd = args[6 : ]->trim()
1176 util.ErrMsg('Argument required')
1178 elseif args == 'restart'
1180 elseif args->stridx('show') == 0
1182 var subcmd = args[5 : ]->trim()
1185 util.ErrMsg('Argument required')
1187 elseif args->stridx('trace') == 0
1189 var subcmd = args[6 : ]->trim()
1190 ServerTraceSet(subcmd)
1192 util.ErrMsg('Argument required')
1195 util.ErrMsg($'LspServer - Unsupported argument "{args}"')
1199 # vim: tabstop=8 shiftwidth=2 softtabstop=2 noexpandtab