]> Sergey Matveev's repositories - vim-lsp.git/blob - autoload/lsp/capabilities.vim
Add support for UTF-8 and UTF-16 offset encoding
[vim-lsp.git] / autoload / lsp / capabilities.vim
1 vim9script
2
3 # Functions for managing the LSP server and client capabilities
4
5 import './options.vim' as opt
6
7 # Process the server capabilities
8 #   interface ServerCapabilities
9 export def ProcessServerCaps(lspserver: dict<any>, caps: dict<any>)
10   var serverEncoding = 'utf-16'
11   if lspserver.caps->has_key('positionEncoding')
12     serverEncoding = lspserver.caps.positionEncoding
13   elseif lspserver.caps->has_key('~additionalInitResult_offsetEncoding')
14     serverEncoding = lspserver.caps['~additionalInitResult_offsetEncoding']
15   endif
16
17   # one of 'utf-8', 'utf-16' or 'utf-32'
18   if serverEncoding == 'utf-8'
19     lspserver.posEncoding = 8
20   elseif serverEncoding == 'utf-16'
21     lspserver.posEncoding = 16
22   else
23     lspserver.posEncoding = 32
24   endif
25
26   if has('patch-9.0.1629') && lspserver.posEncoding != 32
27     lspserver.needOffsetEncoding = true
28   else
29     lspserver.needOffsetEncoding = false
30   endif
31
32   # completionProvider
33   if lspserver.caps->has_key('completionProvider')
34     lspserver.isCompletionProvider = true
35     if lspserver.caps.completionProvider->has_key('resolveProvider')
36       lspserver.isCompletionResolveProvider =
37                         lspserver.caps.completionProvider.resolveProvider
38     else
39       lspserver.isCompletionResolveProvider = false
40     endif
41   else
42     lspserver.isCompletionProvider = false
43     lspserver.isCompletionResolveProvider = false
44   endif
45
46   # definitionProvider
47   if lspserver.caps->has_key('definitionProvider')
48     if lspserver.caps.definitionProvider->type() == v:t_bool
49       lspserver.isDefinitionProvider = lspserver.caps.definitionProvider
50     else
51       lspserver.isDefinitionProvider = true
52     endif
53   else
54     lspserver.isDefinitionProvider = false
55   endif
56
57   # declarationProvider
58   if lspserver.caps->has_key('declarationProvider')
59     if lspserver.caps.declarationProvider->type() == v:t_bool
60       lspserver.isDeclarationProvider = lspserver.caps.declarationProvider
61     else
62       lspserver.isDeclarationProvider = true
63     endif
64   else
65     lspserver.isDeclarationProvider = false
66   endif
67
68   # typeDefinitionProvider
69   if lspserver.caps->has_key('typeDefinitionProvider')
70     if lspserver.caps.typeDefinitionProvider->type() == v:t_bool
71       lspserver.isTypeDefinitionProvider = lspserver.caps.typeDefinitionProvider
72     else
73       lspserver.isTypeDefinitionProvider = true
74     endif
75   else
76     lspserver.isTypeDefinitionProvider = false
77   endif
78
79   # implementationProvider
80   if lspserver.caps->has_key('implementationProvider')
81     if lspserver.caps.implementationProvider->type() == v:t_bool
82       lspserver.isImplementationProvider = lspserver.caps.implementationProvider
83     else
84       lspserver.isImplementationProvider = true
85     endif
86   else
87     lspserver.isImplementationProvider = false
88   endif
89
90   # signatureHelpProvider
91   if lspserver.caps->has_key('signatureHelpProvider')
92     lspserver.isSignatureHelpProvider = true
93   else
94     lspserver.isSignatureHelpProvider = false
95   endif
96
97   # hoverProvider
98   if lspserver.caps->has_key('hoverProvider')
99     if lspserver.caps.hoverProvider->type() == v:t_bool
100       lspserver.isHoverProvider = lspserver.caps.hoverProvider
101     else
102       lspserver.isHoverProvider = true
103     endif
104   else
105     lspserver.isHoverProvider = false
106   endif
107
108   # referencesProvider
109   if lspserver.caps->has_key('referencesProvider')
110     if lspserver.caps.referencesProvider->type() == v:t_bool
111       lspserver.isReferencesProvider = lspserver.caps.referencesProvider
112     else
113       lspserver.isReferencesProvider = true
114     endif
115   else
116     lspserver.isReferencesProvider = false
117   endif
118
119   # documentHighlightProvider
120   if lspserver.caps->has_key('documentHighlightProvider')
121     if lspserver.caps.documentHighlightProvider->type() == v:t_bool
122       lspserver.isDocumentHighlightProvider =
123                                 lspserver.caps.documentHighlightProvider
124     else
125       lspserver.isDocumentHighlightProvider = true
126     endif
127   else
128     lspserver.isDocumentHighlightProvider = false
129   endif
130
131   # documentSymbolProvider
132   if lspserver.caps->has_key('documentSymbolProvider')
133     if lspserver.caps.documentSymbolProvider->type() == v:t_bool
134       lspserver.isDocumentSymbolProvider =
135                                 lspserver.caps.documentSymbolProvider
136     else
137       lspserver.isDocumentSymbolProvider = true
138     endif
139   else
140     lspserver.isDocumentSymbolProvider = false
141   endif
142
143   # documentFormattingProvider
144   if lspserver.caps->has_key('documentFormattingProvider')
145     if lspserver.caps.documentFormattingProvider->type() == v:t_bool
146       lspserver.isDocumentFormattingProvider =
147                                 lspserver.caps.documentFormattingProvider
148     else
149       lspserver.isDocumentFormattingProvider = true
150     endif
151   else
152     lspserver.isDocumentFormattingProvider = false
153   endif
154
155   # callHierarchyProvider
156   if lspserver.caps->has_key('callHierarchyProvider')
157     if lspserver.caps.callHierarchyProvider->type() == v:t_bool
158       lspserver.isCallHierarchyProvider =
159                                 lspserver.caps.callHierarchyProvider
160     else
161       lspserver.isCallHierarchyProvider = true
162     endif
163   else
164     lspserver.isCallHierarchyProvider = false
165   endif
166
167   # typeHierarchyProvider
168   if lspserver.caps->has_key('typeHierarchyProvider')
169     lspserver.isTypeHierarchyProvider = true
170   else
171     lspserver.isTypeHierarchyProvider = false
172   endif
173
174   # renameProvider
175   if lspserver.caps->has_key('renameProvider')
176     if lspserver.caps.renameProvider->type() == v:t_bool
177       lspserver.isRenameProvider = lspserver.caps.renameProvider
178     else
179       lspserver.isRenameProvider = true
180     endif
181   else
182     lspserver.isRenameProvider = false
183   endif
184
185   # codeActionProvider
186   if lspserver.caps->has_key('codeActionProvider')
187     if lspserver.caps.codeActionProvider->type() == v:t_bool
188       lspserver.isCodeActionProvider = lspserver.caps.codeActionProvider
189     else
190       lspserver.isCodeActionProvider = true
191     endif
192   else
193     lspserver.isCodeActionProvider = false
194   endif
195
196   # codeLensProvider
197   if lspserver.caps->has_key('codeLensProvider')
198     lspserver.isCodeLensProvider = true
199     if lspserver.caps.codeLensProvider->has_key('resolveProvider')
200       lspserver.isCodeLensResolveProvider = true
201     else
202       lspserver.isCodeLensResolveProvider = false
203     endif
204   else
205     lspserver.isCodeLensProvider = false
206   endif
207
208   # workspaceSymbolProvider
209   if lspserver.caps->has_key('workspaceSymbolProvider')
210     if lspserver.caps.workspaceSymbolProvider->type() == v:t_bool
211       lspserver.isWorkspaceSymbolProvider =
212                                 lspserver.caps.workspaceSymbolProvider
213     else
214       lspserver.isWorkspaceSymbolProvider = true
215     endif
216   else
217     lspserver.isWorkspaceSymbolProvider = false
218   endif
219
220   # selectionRangeProvider
221   if lspserver.caps->has_key('selectionRangeProvider')
222     if lspserver.caps.selectionRangeProvider->type() == v:t_bool
223       lspserver.isSelectionRangeProvider =
224                                 lspserver.caps.selectionRangeProvider
225     else
226       lspserver.isSelectionRangeProvider = true
227     endif
228   else
229     lspserver.isSelectionRangeProvider = false
230   endif
231
232   # foldingRangeProvider
233   if lspserver.caps->has_key('foldingRangeProvider')
234     if lspserver.caps.foldingRangeProvider->type() == v:t_bool
235       lspserver.isFoldingRangeProvider = lspserver.caps.foldingRangeProvider
236     else
237       lspserver.isFoldingRangeProvider = true
238     endif
239   else
240     lspserver.isFoldingRangeProvider = false
241   endif
242
243   # inlayHintProvider
244   if lspserver.caps->has_key('inlayHintProvider')
245     if lspserver.caps.inlayHintProvider->type() == v:t_bool
246       lspserver.isInlayHintProvider = lspserver.caps.inlayHintProvider
247     else
248       lspserver.isInlayHintProvider = true
249     endif
250   else
251     lspserver.isInlayHintProvider = false
252   endif
253
254   # clangdInlayHintsProvider
255   if lspserver.caps->has_key('clangdInlayHintsProvider')
256     lspserver.isClangdInlayHintsProvider =
257                                         lspserver.caps.clangdInlayHintsProvider
258   else
259     lspserver.isClangdInlayHintsProvider = false
260   endif
261
262   # textDocumentSync capabilities
263   lspserver.supportsDidSave = false
264   # Default to TextDocumentSyncKind.None
265   lspserver.textDocumentSync = 0
266   if lspserver.caps->has_key('textDocumentSync')
267     if lspserver.caps.textDocumentSync->type() == v:t_bool
268         || lspserver.caps.textDocumentSync->type() == v:t_number
269       lspserver.supportsDidSave = lspserver.caps.textDocumentSync
270       lspserver.textDocumentSync = lspserver.caps.textDocumentSync
271     elseif lspserver.caps.textDocumentSync->type() == v:t_dict
272       # "save"
273       if lspserver.caps.textDocumentSync->has_key('save')
274         if lspserver.caps.textDocumentSync.save->type() == v:t_bool
275             || lspserver.caps.textDocumentSync.save->type() == v:t_number
276           lspserver.supportsDidSave = lspserver.caps.textDocumentSync.save
277         elseif lspserver.caps.textDocumentSync.save->type() == v:t_dict
278           lspserver.supportsDidSave = true
279         endif
280       endif
281       # "change"
282       if lspserver.caps.textDocumentSync->has_key('change')
283         lspserver.textDocumentSync = lspserver.caps.textDocumentSync.change
284       endif
285     endif
286   endif
287 enddef
288
289 # Return all the LSP client capabilities
290 export def GetClientCaps(): dict<any>
291   # client capabilities (ClientCapabilities)
292   var clientCaps: dict<any> = {
293     workspace: {
294       workspaceFolders: true,
295       applyEdit: true,
296       configuration: true
297     },
298     textDocument: {
299       callHierarchy: {
300         dynamicRegistration: false
301       },
302       codeAction: {
303         dynamicRegistration: false,
304         codeActionLiteralSupport: {
305           codeActionKind: {
306             valueSet: ['', 'quickfix', 'refactor', 'refactor.extract',
307                         'refactor.inline', 'refactor.rewrite', 'source',
308                         'source.organizeImports']
309           }
310         },
311         isPreferredSupport: true,
312         disabledSupport: true
313       },
314       codeLens: {
315         dynamicRegistration: false
316       },
317       completion: {
318         dynamicRegistration: false,
319         completionItem: {
320           documentationFormat: ['markdown', 'plaintext'],
321           resolveSupport: {properties: ['detail', 'documentation']},
322           snippetSupport: opt.lspOptions.snippetSupport
323         },
324         completionItemKind: {valueSet: range(1, 25)}
325       },
326       documentSymbol: {
327         dynamicRegistration: false,
328         hierarchicalDocumentSymbolSupport: true,
329         symbolKind: {valueSet: range(1, 25)}
330       },
331       hover: {
332         contentFormat: ['markdown', 'plaintext']
333       },
334       foldingRange: {lineFoldingOnly: true},
335       inlayHint: {dynamicRegistration: false},
336       synchronization: {
337         didSave: true
338       },
339       declaration: {linkSupport: true},
340       definition: {linkSupport: true},
341       typeDefinition: {linkSupport: true},
342       implementation: {linkSupport: true},
343       signatureHelp: {
344         signatureInformation: {
345           documentationFormat: ['markdown', 'plaintext'],
346           activeParameterSupport: true
347         }
348       }
349     },
350     window: {},
351     general: {
352       # Currently we always send character count as position offset,
353       # which meanas only utf-32 is supported.
354       # Adding utf-16 simply for good mesure, as I'm scared some servers will
355       # give up if they don't support utf-32 only.
356       positionEncodings: ['utf-32', 'utf-16']
357     },
358     # This is the way clangd expects to be informated about supported encodings:
359     # https://clangd.llvm.org/extensions#utf-8-offsets
360     offsetEncoding: ['utf-32', 'utf-16']
361   }
362
363   # Vim patch 1629 is needed to properly encode/decode UTF-16 offsets
364   if has('patch-9.0.1629')
365     clientCaps.general.positionEncodings = ['utf-32', 'utf-16', 'utf-8']
366     clientCaps.offsetEncoding = ['utf-32', 'utf-16', 'utf-8']
367   endif
368
369   return clientCaps
370 enddef
371
372 # vim: tabstop=8 shiftwidth=2 softtabstop=2