11
11
import urllib
12
12
import urllib .parse
13
13
from pathlib import Path
14
- from typing import Any , Awaitable , Callable , Sequence , Type
14
+ from typing import (
15
+ Any ,
16
+ Awaitable ,
17
+ Callable ,
18
+ Literal ,
19
+ Sequence ,
20
+ Type ,
21
+ TypedDict ,
22
+ )
23
+ import uuid
15
24
import warnings
16
25
17
26
import attrs
36
45
CallHierarchyItem ,
37
46
CallHierarchyPrepareParams ,
38
47
ClientCapabilities ,
48
+ DidChangeConfigurationParams ,
39
49
DidOpenTextDocumentParams ,
40
50
ExecuteCommandParams ,
41
51
InitializeParams ,
@@ -201,8 +211,45 @@ def connection_made(self, transport: asyncio.Transport): # type: ignore
201
211
return super ().connection_made (transport )
202
212
203
213
214
+ class OnTypeFormattingSetting (TypedDict ):
215
+ indentOnly : bool
216
+
217
+
218
+ class ALSSettings (
219
+ TypedDict ,
220
+ # This indicates that the dictionary keys can be omitted, they are not required to
221
+ # appear
222
+ total = False ,
223
+ ):
224
+ """This class helps create a dictionary of ALS settings. It has to be manually
225
+ updated when new settings are added.
226
+
227
+ So if you see a missing setting that you need, consider adding it.
228
+ """
229
+
230
+ defaultCharset : str | None
231
+ displayMethodAncestryOnNavigation : bool | None
232
+ documentationStyle : Literal ["gnat" , "leading" ] | None
233
+ enableDiagnostics : bool | None
234
+ enableIndexing : bool | None
235
+ foldComments : bool | None
236
+ followSymlinks : bool | None
237
+ insertWithClauses : bool | None
238
+ logThreshold : int | None
239
+ namedNotationThreshold : int | None
240
+ onTypeFormatting : OnTypeFormattingSetting | None
241
+ projectDiagnostics : bool | None
242
+ projectFile : str | None
243
+ relocateBuildTree : str | None
244
+ renameInComments : bool | None
245
+ rootDir : str | None
246
+ scenarioVariables : dict [str , str ] | None
247
+ useCompletionSnippets : bool | None
248
+ useGnatformat : bool | None
249
+
250
+
204
251
class ALSLanguageClient (LanguageClient ):
205
- """This class provides methods to communicate with a language server ."""
252
+ """This class provides methods to communicate with the Ada Language Server ."""
206
253
207
254
def __init__ (
208
255
self ,
@@ -215,6 +262,63 @@ def __init__(
215
262
216
263
super ().__init__ (* args , configuration = configuration , ** kwargs )
217
264
265
+ async def getObjectDir (self ) -> str | None :
266
+ """Send the "als-object-dir" command to obtain the object dir of the currently
267
+ loaded project.
268
+ """
269
+ return await self .workspace_execute_command_async (
270
+ ExecuteCommandParams ("als-object-dir" )
271
+ )
272
+
273
+ async def getObjDirBasename (self ) -> str | None :
274
+ """Send the "als-object-dir" command to obtain the object dir of the currently
275
+ loaded project, and return its basename.
276
+ """
277
+ obj_dir = await self .getObjectDir ()
278
+ if obj_dir is not None :
279
+ return os .path .basename (obj_dir )
280
+ else :
281
+ return None
282
+
283
+ def didChangeConfig (self , settings : ALSSettings ) -> None :
284
+ """Send a workspace/didChangeConfiguration notification with as set of ALS
285
+ settings.
286
+ """
287
+ self .workspace_did_change_configuration (
288
+ DidChangeConfigurationParams (settings = {"ada" : settings })
289
+ )
290
+
291
+ def didOpenVirtual (
292
+ self , uri : str | None = None , language_id = "ada" , version = 0 , text : str = ""
293
+ ) -> str :
294
+ """Send a didOpen notification for a file that doesn't exist on disk.
295
+
296
+ If the `uri` parameter is omitted, a random one is generated
297
+ automatically with a `.ads` extension.
298
+
299
+ :param uri: the URI of the file. If None, that will be automatically
300
+ generated and returned as a result of the call.
301
+ :param language_id: the language_id parameter of the LSP notification.
302
+ :param version: the version parameter of the LSP notification. Defaults
303
+ to 0.
304
+ :param text: the text parameter of the LSP notification.
305
+
306
+ :return: the URI of the document
307
+ """
308
+ if uri is None :
309
+ path = str (uuid .uuid4 ())
310
+ if language_id == "ada" :
311
+ path += ".ads"
312
+ else :
313
+ path += "." + language_id
314
+ uri = URI (path )
315
+
316
+ self .text_document_did_open (
317
+ DidOpenTextDocumentParams (TextDocumentItem (uri , language_id , version , text ))
318
+ )
319
+
320
+ return uri
321
+
218
322
219
323
def als_client_factory () -> ALSLanguageClient :
220
324
"""This function is an ugly copy-paste of pytest_lsp.make_test_lsp_client. It is
@@ -647,13 +751,16 @@ def to_str(item: tuple[str, int]):
647
751
648
752
async def awaitIndexingEnd (lsp : LanguageClient ):
649
753
"""Wait until the ALS finishes indexing."""
754
+ LOG .info ("Awaiting indexing start and end" )
755
+
650
756
indexing_progress = None
651
757
while indexing_progress is None :
652
758
await asyncio .sleep (0.2 )
653
- LOG .info (
654
- "Awaiting indexing progress - lsp.progress_reports = %s" ,
655
- lsp .progress_reports ,
656
- )
759
+ if args .verbose >= 2 :
760
+ LOG .debug (
761
+ "Awaiting indexing progress - lsp.progress_reports = %s" ,
762
+ lsp .progress_reports ,
763
+ )
657
764
indexing_progress = next (
658
765
(prog for prog in lsp .progress_reports if "indexing" in str (prog )),
659
766
None ,
@@ -664,7 +771,8 @@ async def awaitIndexingEnd(lsp: LanguageClient):
664
771
last_progress = lsp .progress_reports [indexing_progress ][- 1 ]
665
772
while not isinstance (last_progress , WorkDoneProgressEnd ):
666
773
await asyncio .sleep (0.2 )
667
- LOG .info ("Waiting for indexing end - last_progress = %s" , last_progress )
774
+ if args .verbose >= 2 :
775
+ LOG .debug ("Waiting for indexing end - last_progress = %s" , last_progress )
668
776
last_progress = lsp .progress_reports [indexing_progress ][- 1 ]
669
777
670
778
LOG .info ("Received indexing end message" )
0 commit comments