1111import urllib
1212import urllib .parse
1313from 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
1524import warnings
1625
1726import attrs
3645 CallHierarchyItem ,
3746 CallHierarchyPrepareParams ,
3847 ClientCapabilities ,
48+ DidChangeConfigurationParams ,
3949 DidOpenTextDocumentParams ,
4050 ExecuteCommandParams ,
4151 InitializeParams ,
@@ -201,8 +211,45 @@ def connection_made(self, transport: asyncio.Transport): # type: ignore
201211 return super ().connection_made (transport )
202212
203213
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+
204251class 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 ."""
206253
207254 def __init__ (
208255 self ,
@@ -215,6 +262,63 @@ def __init__(
215262
216263 super ().__init__ (* args , configuration = configuration , ** kwargs )
217264
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+
218322
219323def als_client_factory () -> ALSLanguageClient :
220324 """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]):
647751
648752async def awaitIndexingEnd (lsp : LanguageClient ):
649753 """Wait until the ALS finishes indexing."""
754+ LOG .info ("Awaiting indexing start and end" )
755+
650756 indexing_progress = None
651757 while indexing_progress is None :
652758 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+ )
657764 indexing_progress = next (
658765 (prog for prog in lsp .progress_reports if "indexing" in str (prog )),
659766 None ,
@@ -664,7 +771,8 @@ async def awaitIndexingEnd(lsp: LanguageClient):
664771 last_progress = lsp .progress_reports [indexing_progress ][- 1 ]
665772 while not isinstance (last_progress , WorkDoneProgressEnd ):
666773 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 )
668776 last_progress = lsp .progress_reports [indexing_progress ][- 1 ]
669777
670778 LOG .info ("Received indexing end message" )
0 commit comments