]> Sergey Matveev's repositories - vim-lsp.git/blob - autoload/lsp/buffer.vim
fixup! fix: send buffer text on textDocument/didSave
[vim-lsp.git] / autoload / lsp / buffer.vim
1 vim9script
2
3 # Functions for managing the per-buffer LSP server information
4
5 import './util.vim'
6
7 # A buffer can have one or more attached language servers.  The
8 # "bufnrToServers" Dict contains the list of language servers attached to a
9 # buffer. The buffer number is the key for the "bufnrToServers" Dict.  The
10 # value is the List of attached language servers.
11 var bufnrToServers: dict<list<dict<any>>> = {}
12
13 # Add "lspserver" to "bufnrToServers" map for buffer "bnr".
14 export def BufLspServerSet(bnr: number, lspserver: dict<any>)
15   if !bufnrToServers->has_key(bnr)
16     bufnrToServers[bnr] = []
17   endif
18
19   bufnrToServers[bnr]->add(lspserver)
20 enddef
21
22 # Remove "lspserver" from "bufnrToServers" map for buffer "bnr".
23 export def BufLspServerRemove(bnr: number, lspserver: dict<any>)
24   if !bufnrToServers->has_key(bnr)
25     return
26   endif
27
28   var servers: list<dict<any>> = bufnrToServers[bnr]
29   servers = servers->filter((key, srv) => srv.id != lspserver.id)
30
31   if servers->empty()
32     bufnrToServers->remove(bnr)
33   else
34     bufnrToServers[bnr] = servers
35   endif
36 enddef
37
38 var SupportedCheckFns = {
39   callHierarchy: (lspserver) => lspserver.isCallHierarchyProvider,
40   codeAction: (lspserver) => lspserver.isCodeActionProvider,
41   codeLens: (lspserver) => lspserver.isCodeLensProvider,
42   completion: (lspserver) => lspserver.isCompletionProvider,
43   declaration: (lspserver) => lspserver.isDeclarationProvider,
44   definition: (lspserver) => lspserver.isDefinitionProvider,
45   documentFormatting: (lspserver) => lspserver.isDocumentFormattingProvider,
46   documentHighlight: (lspserver) => lspserver.isDocumentHighlightProvider,
47   documentSymbol: (lspserver) => lspserver.isDocumentSymbolProvider,
48   foldingRange: (lspserver) => lspserver.isFoldingRangeProvider,
49   hover: (lspserver) => lspserver.isHoverProvider,
50   implementation: (lspserver) => lspserver.isImplementationProvider,
51   inlayHint: (lspserver) => lspserver.isInlayHintProvider ||
52                                         lspserver.isClangdInlayHintsProvider,
53   references: (lspserver) => lspserver.isReferencesProvider,
54   rename: (lspserver) => lspserver.isRenameProvider,
55   selectionRange: (lspserver) => lspserver.isSelectionRangeProvider,
56   signatureHelp: (lspserver) => lspserver.isSignatureHelpProvider,
57   typeDefinition: (lspserver) => lspserver.isTypeDefinitionProvider,
58   typeHierarchy: (lspserver) => lspserver.isTypeHierarchyProvider,
59   workspaceSymbol: (lspserver) => lspserver.isWorkspaceSymbolProvider
60 }
61
62 # Returns the LSP server for the buffer "bnr".  If "feature" is specified,
63 # then returns the LSP server that provides the "feature".
64 # Returns an empty dict if the server is not found.
65 export def BufLspServerGet(bnr: number, feature: string = null_string): dict<any>
66   if !bufnrToServers->has_key(bnr)
67     return {}
68   endif
69
70   if bufnrToServers[bnr]->empty()
71     return {}
72   endif
73
74   if feature == null_string
75     return bufnrToServers[bnr][0]
76   endif
77
78   if !SupportedCheckFns->has_key(feature)
79     # If this happns it is a programming error, and should be fixed in the
80     # source code
81     :throw $'Error: ''{feature}'' is not a valid feature'
82   endif
83
84   var SupportedCheckFn = SupportedCheckFns[feature]
85
86   var possibleLSPs: list<dict<any>> = []
87
88   for lspserver in bufnrToServers[bnr]
89     if !lspserver.ready || !SupportedCheckFn(lspserver)
90       continue
91     endif
92
93     possibleLSPs->add(lspserver)
94   endfor
95
96   if possibleLSPs->empty()
97     return {}
98   endif
99
100   # LSP server is configured to be a provider for "feature"
101   for lspserver in possibleLSPs
102     var has_feature: bool = lspserver.features->get(feature, false)
103     if has_feature
104       return lspserver
105     endif
106   endfor
107
108   # Return the first LSP server that supports "feature" and doesn't have it
109   # disabled
110   for lspserver in possibleLSPs
111     if lspserver.featureEnabled(feature)
112       return lspserver
113     endif
114   endfor
115
116   return {}
117 enddef
118
119 # Returns the LSP server for the buffer "bnr" and with ID "id". Returns an empty
120 # dict if the server is not found.
121 export def BufLspServerGetById(bnr: number, id: number): dict<any>
122   if !bufnrToServers->has_key(bnr)
123     return {}
124   endif
125
126   for lspserver in bufnrToServers[bnr]
127     if lspserver.id == id
128       return lspserver
129     endif
130   endfor
131
132   return {}
133 enddef
134
135 # Returns the LSP servers for the buffer "bnr". Returns an empty list if the
136 # servers are not found.
137 export def BufLspServersGet(bnr: number): list<dict<any>>
138   if !bufnrToServers->has_key(bnr)
139     return []
140   endif
141
142   return bufnrToServers[bnr]
143 enddef
144
145 # Returns the LSP server for the current buffer with the optionally "feature".
146 # Returns an empty dict if the server is not found.
147 export def CurbufGetServer(feature: string = null_string): dict<any>
148   return BufLspServerGet(bufnr(), feature)
149 enddef
150
151 # Returns the LSP servers for the current buffer. Returns an empty list if the
152 # servers are not found.
153 export def CurbufGetServers(): list<dict<any>>
154   return BufLspServersGet(bufnr())
155 enddef
156
157 export def BufHasLspServer(bnr: number): bool
158   var lspserver = BufLspServerGet(bnr)
159
160   return !lspserver->empty()
161 enddef
162
163 # Returns the LSP server for the current buffer with the optinally "feature" if
164 # it is running and is ready.
165 # Returns an empty dict if the server is not found or is not ready.
166 export def CurbufGetServerChecked(feature: string = null_string): dict<any>
167   var fname: string = @%
168   if fname->empty() || &filetype->empty()
169     return {}
170   endif
171
172   var lspserver: dict<any> = CurbufGetServer(feature)
173   if lspserver->empty()
174     if feature == null_string
175       util.ErrMsg($'Language server for "{&filetype}" file type is not found')
176     else
177       util.ErrMsg($'Language server for "{&filetype}" file type supporting "{feature}" feature is not found')
178     endif
179     return {}
180   endif
181   if !lspserver.running
182     util.ErrMsg($'Language server for "{&filetype}" file type is not running')
183     return {}
184   endif
185   if !lspserver.ready
186     util.ErrMsg($'Language server for "{&filetype}" file type is not ready')
187     return {}
188   endif
189
190   return lspserver
191 enddef
192
193 # vim: tabstop=8 shiftwidth=2 softtabstop=2