#!/usr/bin/env python import os import os.path from os.path import join """ Script to generate the 'generated' parts of the code """ LSP_Messages_Generic_Header = """-- Automatically generated, do not edit. with Ada.Tags; with LSP.Generic_{kind}s; with LSP.JSON_Streams; with LSP.Server_{kind}_Receivers; use LSP.Server_{kind}_Receivers; package LSP.Messages.Server_{kind}s is type Server_{kind} is abstract new LSP.Messages.{kind}Message{record}; function Decode (JS : not null access LSP.JSON_Streams.JSON_Stream) return Server_{kind} is abstract; procedure Visit (Self : Server_{kind}; Handler : access Server_{kind}_Receiver'Class) is abstract; function Method_To_Tag (Method : VSS.Strings.Virtual_String) return Ada.Tags.Tag; -- For given LSP method return a corresponding message type tag """ C_Method_Function_Snippet = """ function On_{request_name}_Request (Self : access Server_Request_Handler; Request : LSP.Messages.Server_Requests.{request_name}_Request) return LSP.Messages.Server_Responses.{response_name} is abstract; """ C_Method_Procedure_Snippet = """ procedure On_{request_name}_{kind} (Self : access Server_{kind}_Receiver; Value : LSP.Messages.{params_name}) is abstract; """ C_Method_Procedure_Snippet_Noparam = """ procedure On_{request_name}_{kind} (Self : access Server_{kind}_Receiver) is abstract; """ C_Method_Request_Snippet = """ procedure On_{request_name}_{kind} (Self : access Server_{kind}_Receiver; Value : LSP.Messages.Server_{kind}s.{request_name}_{kind}) is abstract; """ LSP_Messages_Generic_Body_Header = """-- Automatically generated, do not edit. package body LSP.Messages.Server_{kind}s is -- These messages are sent from client to server. Map : Maps.Map; function Method_To_Tag (Method : VSS.Strings.Virtual_String) return Ada.Tags.Tag is begin return Method_To_Tag (Map, Method); end Method_To_Tag; """ C_Method_Visit_Body_Snippet = """ overriding procedure Visit (Self : {request_name}_{kind}; Handler : access Server_{kind}_Receiver'Class) is begin Handler.On_{request_name}_{kind} (Self{params}); end Visit; """ C_Method_Visit_Body_Snippet_Noparams = """ overriding procedure Visit (Self : {request_name}_{kind}; Handler : access Server_{kind}_Receiver'Class) is pragma Unreferenced (Self); begin Handler.On_{request_name}_{kind}; end Visit; """ C_Method_Decode_Body_Snippet = """ overriding function Decode (JS : not null access LSP.JSON_Streams.JSON_Stream) return {request_name}_{kind} is begin return V : {request_name}_{kind} do {kind}Message'Read (JS, {kind}Message (V)); end return; end Decode; """ C_Handler_Procedure_Body = """-- Automatically generated, do not edit. with LSP.Messages.Server_Notifications; use LSP.Messages.Server_Notifications; procedure LSP.Servers.Handle_{kind} (Self : not null LSP.Server_Notification_Handlers .Server_Notification_Handler_Access; {kind} : LSP.Messages.{kind}Message'Class) is begin {handler_snippets} end LSP.Servers.Handle_{kind}; """ C_Handler_Function_Body = """-- Automatically generated, do not edit. with LSP.Messages.Server_Requests; use LSP.Messages.Server_Requests; function LSP.Servers.Handle_{kind} (Self : not null Server_Request_Handlers .Server_Request_Handler_Access; {kind} : LSP.Messages.{kind}Message'Class) return LSP.Messages.ResponseMessage'Class is begin {handler_snippets} return LSP.Messages.ResponseMessage' (Is_Error => True, jsonrpc => <>, id => <>, error => (Is_Set => True, Value => (code => LSP.Messages.MethodNotFound, message => "The {kind} handler doesn't support this", others => <>))); end LSP.Servers.Handle_{kind}; """ C_Handler_Snippet_Function = """ if {kind} in {request_name}_{kind}'Class then declare R : LSP.Messages.ResponseMessage'Class := Self.On_{request_name}_{kind} ({request_name}_{kind} ({kind})); begin R.jsonrpc := "2.0"; R.id := Request.id; return R; end; end if; """ C_Handler_Snippet_Procedure = """ if {kind} in {request_name}_{kind}'Class then Self.On_{request_name}_{kind} (({request_name}_{kind} ({kind}).params)); return; end if; """ C_Handler_Snippet_Procedure_Noparams = """ if {kind} in {request_name}_{kind}'Class then Self.On_{request_name}_{kind}; return; end if; """ LSP_Messages_Body_Begin = """ begin""" LSP_Messages_Insert = """ Map.Insert ("{protocol_name}", {request_name}_{kind}'Tag);""" LSP_Messages_Generic_Footer = """ end LSP.Messages.Server_{kind}s; """ LSP_Messages_Generic_Type_Snippet = """ package {request_name}_{kind}s is new LSP.Generic_{kind}s (Server_{kind}, {params_name}, Server_{kind}_Receiver'Class); type {request_name}_{kind} is new {request_name}_{kind}s.{kind} with null record; overriding procedure Visit (Self : {request_name}_{kind}; Handler : access Server_{kind}_Receiver'Class); """ LSP_Messages_Generic_Type_Snippet_Noparams = """ type {request_name}_{kind} is new Server_{kind} with null record; overriding function Decode (JS : not null access LSP.JSON_Streams.JSON_Stream) return {request_name}_{kind}; overriding procedure Visit (Self : {request_name}_{kind}; Handler : access Server_{kind}_Receiver'Class); """ LSP_Server_Handlers_Header = """-- Automatically generated, do not edit. pragma Style_Checks (Off); with LSP.Messages.Server_Requests; with LSP.Messages.Server_Responses; package LSP.Server_Request_{handler}s is type Server_Request_{handler} is limited interface; type Server_Request_{handler}_Access is access all Server_Request_{handler}'Class; -- A type which represents a handler which supports reacting -- to Requests. Clients implementing this interface should override -- the *_Request methods, and clients making use of this interface -- should simply call Handle_Request when they want to dispatch -- a Request to the handler. """ LSP_Server_Handlers_Footer = """ end LSP.Server_{kind}_{handler}s; """ LSP_Server_Recievers_Header = """-- Automatically generated, do not edit. limited with LSP.Messages{extra_with}; package LSP.Server_{kind}_{handler}s is type Server_{kind}_{handler} is limited interface; type Server_{kind}_{handler}_Access is access all Server_{kind}_{handler}'Class; -- A type which represents a handler which supports reacting -- to {kind}s. Clients implementing this interface should override -- the *_{kind} methods, and clients making use of this interface -- should simply call corresponding method when they want to dispatch -- a {kind} to the handler. """ basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) REQUESTS = [ ('initialize', 'Initialize', 'InitializeParams', 'Initialize_Response'), ('shutdown', 'Shutdown', None, 'Shutdown_Response'), ('textDocument/codeAction', 'CodeAction', 'CodeActionParams', 'CodeAction_Response'), ('textDocument/completion', 'Completion', 'TextDocumentPositionParams', 'Completion_Response'), ('completionItem/resolve', 'CompletionItemResolve', 'CompletionItem', 'CompletionItemResolve_Response'), ('textDocument/definition', 'Definition', 'DefinitionParams', 'Location_Link_Response'), ('textDocument/declaration', 'Declaration', 'DeclarationParams', 'Location_Link_Response'), ('textDocument/implementation', 'Implementation', 'ImplementationParams', 'Location_Link_Response'), ('textDocument/typeDefinition', 'Type_Definition', 'TextDocumentPositionParams', 'Location_Link_Response'), ('textDocument/documentHighlight', 'Highlight', 'TextDocumentPositionParams', 'Highlight_Response'), ('textDocument/hover', 'Hover', 'TextDocumentPositionParams', 'Hover_Response'), ('textDocument/documentLink', 'Document_Links', 'DocumentLinkParams', 'Links_Response'), ('textDocument/references', 'References', 'ReferenceParams', 'Location_Response'), ('textDocument/signatureHelp', 'Signature_Help', 'SignatureHelpParams', 'SignatureHelp_Response'), ('textDocument/documentSymbol', 'Document_Symbols', 'DocumentSymbolParams', 'Symbol_Response'), ('textDocument/rename', 'Rename', 'RenameParams', 'Rename_Response'), ('textDocument/prepareRename', 'Prepare_Rename', 'PrepareRenameParams', 'Prepare_Rename_Response'), ('textDocument/executeCommand', 'Execute_Command', 'ExecuteCommandParams', 'ExecuteCommand_Response'), ('textDocument/documentColor', 'Document_Color', 'DocumentColorParams', 'DocumentColor_Response'), ('textDocument/colorPresentation', 'Color_Presentation', 'ColorPresentationParams', 'ColorPresentation_Response'), ('textDocument/foldingRange', 'Folding_Range', 'FoldingRangeParams', 'FoldingRange_Response'), ('textDocument/formatting', 'Formatting', 'DocumentFormattingParams', 'Formatting_Response'), ('textDocument/rangeFormatting', 'Range_Formatting', 'DocumentRangeFormattingParams', 'Range_Formatting_Response'), ('textDocument/onTypeFormatting', 'On_Type_Formatting', 'DocumentOnTypeFormattingParams', 'On_Type_Formatting_Response'), ('textDocument/selectionRange', 'Selection_Range', 'SelectionRangeParams', 'SelectionRange_Response'), ('textDocument/semanticTokens/full', 'Document_Tokens_Full', 'SemanticTokensParams', 'SemanticTokens_Response'), ('textDocument/semanticTokens/range', 'Document_Tokens_Range', 'SemanticTokensRangeParams', 'SemanticTokens_Response'), ('textDocument/prepareCallHierarchy', 'Prepare_Call_Hierarchy', 'CallHierarchyPrepareParams', 'PrepareCallHierarchy_Response'), ('callHierarchy/incomingCalls', 'Incoming_Calls', 'CallHierarchyIncomingCallsParams', 'IncomingCalls_Response'), ('callHierarchy/outgoingCalls', 'Outgoing_Calls', 'CallHierarchyOutgoingCallsParams', 'OutgoingCalls_Response'), ('workspace/symbol', 'Workspace_Symbols', 'WorkspaceSymbolParams', 'Symbol_Response'), ('workspace/executeCommand', 'Workspace_Execute_Command', 'ExecuteCommandParams', 'ExecuteCommand_Response'), ('workspace/willCreateFiles', 'Workspace_Will_Create_Files', 'CreateFilesParams', 'WillCreateFiles_Response'), ('workspace/willRenameFiles', 'Workspace_Will_Rename_Files', 'RenameFilesParams', 'WillRenameFiles_Response'), ('workspace/willDeleteFiles', 'Workspace_Will_Delete_Files', 'DeleteFilesParams', 'WillDeleteFiles_Response'), # ALS-specific requests ('textDocument/alsShowDependencies', 'ALS_Show_Dependencies', 'ALS_ShowDependenciesParams', 'ALS_ShowDependencies_Response'), ('workspace/alsSourceDirs', 'ALS_Source_Dirs', None, 'ALS_SourceDirs_Response'), ('$/alsDebug', 'ALS_Debug', 'ALSDebugParams', 'ALS_Debug_Response'), ('$/alsCheckSyntax', 'ALS_Check_Syntax', 'ALS_Check_Syntax_Params', 'ALS_Check_Syntax_Response'), ('$/glsMains', 'GLS_Mains', None, 'GLS_Mains_Response'), ('$/glsExecutables', 'GLS_Executables', None, 'GLS_Executables_Response'), ('$/glsObjectDir', 'GLS_Object_Dir', None, 'GLS_Object_Dir_Response'), ('$/glsProjectFile', 'GLS_Project_File', None, 'GLS_Project_File_Response'), ] # Names of requests in the form (protocol name, Ada name, parameter name, # response name) NOTIFICATIONS = [ ('initialized', 'Initialized', None), ('exit', 'Exit', None), ('workspace/didChangeConfiguration', 'DidChangeConfiguration', 'DidChangeConfigurationParams'), ('workspace/didChangeWorkspaceFolders', 'DidChangeWorkspaceFolders', 'DidChangeWorkspaceFoldersParams'), ('workspace/didChangeWatchedFiles', 'DidChangeWatchedFiles', 'DidChangeWatchedFilesParams'), ('workspace/didCreateFiles', 'DidCreateFiles', 'CreateFilesParams'), ('workspace/didRenameFiles', 'DidRenameFiles', 'RenameFilesParams'), ('workspace/didDeleteFiles', 'DidDeleteFiles', 'DeleteFilesParams'), ('$/cancelRequest', 'Cancel', 'CancelParams'), ('$/setTrace', 'SetTrace', 'SetTraceParams'), # TODO: rename these to TextDocumentDidOpen/DidChange/DidSave/DidClose? ('textDocument/didOpen', 'DidOpenTextDocument', 'DidOpenTextDocumentParams'), ('textDocument/didChange', 'DidChangeTextDocument', 'DidChangeTextDocumentParams'), ('textDocument/didSave', 'DidSaveTextDocument', 'DidSaveTextDocumentParams'), ('textDocument/didClose', 'DidCloseTextDocument', 'DidCloseTextDocumentParams'), ] def write_message_types(): """ Write source/protocol/lsp-messages-request.* """ def write_package(data_array, kind, record, ads_name, handler_is_procedure): """Factorization function""" # Write the .ads with open(ads_name, 'w') as ads: ads.write(LSP_Messages_Generic_Header.format(kind=kind, record=record)) for l in data_array: request_name = l[1] params_name = l[2] if params_name: ads.write(LSP_Messages_Generic_Type_Snippet.format( request_name=request_name, params_name=params_name, kind=kind)) else: ads.write( LSP_Messages_Generic_Type_Snippet_Noparams.format( request_name=request_name, kind=kind)) ads.write(LSP_Messages_Generic_Footer.format(kind=kind)) def write_body(data_array, kind, adb_name, handler_is_procedure): """Factorization function""" # Write the .adb with open(adb_name, 'w') as adb: adb.write(LSP_Messages_Generic_Body_Header.format(kind=kind)) for l in data_array: request_name = l[1] params_name = l[2] if not params_name: adb.write( C_Method_Decode_Body_Snippet.format( request_name=request_name, kind=kind)) if params_name or not handler_is_procedure: adb.write( C_Method_Visit_Body_Snippet.format( request_name=request_name, kind=kind, params=".params" if handler_is_procedure else "")) else: adb.write( C_Method_Visit_Body_Snippet_Noparams.format( request_name=request_name, kind=kind)) adb.write(LSP_Messages_Body_Begin.format(kind=kind)) for l in data_array: protocol_name = l[0] request_name = l[1] params_name = l[2] adb.write(LSP_Messages_Insert.format( protocol_name=protocol_name, request_name=request_name, kind=kind)) adb.write(LSP_Messages_Generic_Footer.format(kind=kind)) gen_dir = join(basedir, 'source', 'protocol', 'generated') write_package(REQUESTS, 'Request', """ with record\n Canceled : Boolean := False with Atomic;\n end record""", join(gen_dir, 'lsp-messages-server_requests.ads'), False) write_package(NOTIFICATIONS, 'Notification', '\n with null record', join(gen_dir, 'lsp-messages-server_notifications.ads'), True) write_body(NOTIFICATIONS, 'Notification', join(gen_dir, 'lsp-messages-server_notifications.adb'), True) write_body(REQUESTS, 'Request', join(gen_dir, 'lsp-messages-server_requests.adb'), False) def write_handle_request(): def write_package(data_array, kind, adb_name, handler_is_procedure): """Factorization function""" # Write the .adb with open(adb_name, 'w') as adb: handler_snippets = "" # Generate the snippets for l in data_array: protocol_name = l[0] request_name = l[1] if handler_is_procedure: handler_snippets += \ C_Handler_Snippet_Procedure.format( request_name=request_name, kind=kind) else: handler_snippets += \ C_Handler_Snippet_Function.format( request_name=request_name, kind=kind) if handler_is_procedure: adb.write(C_Handler_Procedure_Body.format( kind=kind, handler_snippets=handler_snippets)) else: adb.write(C_Handler_Function_Body.format( kind=kind, handler_snippets=handler_snippets)) gen_dir = join(basedir, 'source', 'server', 'generated') write_package(REQUESTS, 'Request', join(gen_dir, 'lsp-servers-handle_request.adb'), False) def write_server_handlers(): """ Write source/server/lsp-server_{request/notification}_handlers.ads """ def write_package(data_array, handler_name, ads_name, handler_is_procedure): """Factorization function""" # Write the .ads with open(ads_name, 'w') as ads: ads.write(LSP_Server_Handlers_Header.format( handler=handler_name)) for l in data_array: ads.write( C_Method_Function_Snippet.format( request_name=l[1], response_name=l[3])) ads.write(""" procedure Handle_Error (Self : access Server_Request_Handler) is null; -- This procedure will be called when an unexpected error is raised in the -- request processing loop. """) ads.write(LSP_Server_Handlers_Footer.format( kind='Request', handler=handler_name)) gen_dir = join(basedir, 'source', 'server', 'generated') write_package(REQUESTS, 'Handler', join(gen_dir, 'lsp-server_request_handlers.ads'), False) def write_server_receivers(): """ Write source/server/lsp-server_{request/notification}_handlers.ads """ def write_package(data_array, kind, handler_name, ads_name, is_request): """Factorization function""" # Write the .ads with open(ads_name, 'w') as ads: ads.write(LSP_Server_Recievers_Header.format( kind=kind, handler=handler_name, extra_with=".Server_Requests" if is_request else"")) for l in data_array: request_name = l[1] params_name = l[2] if params_name: if is_request: ads.write( C_Method_Request_Snippet.format( request_name=request_name, params_name=params_name, response_name=l[3], kind=kind)) else: ads.write( C_Method_Procedure_Snippet.format( request_name=request_name, params_name=params_name, kind=kind)) else: if is_request: ads.write( C_Method_Request_Snippet.format( request_name=request_name, params_name=params_name, response_name=l[3], kind=kind)) else: ads.write( C_Method_Procedure_Snippet_Noparam.format( request_name=request_name, kind=kind)) ads.write(LSP_Server_Handlers_Footer.format( kind=kind, handler=handler_name)) gen_dir = join(basedir, 'source', 'protocol', 'generated') write_package(REQUESTS, 'Request', 'Receiver', join(gen_dir, 'lsp-server_request_receivers.ads'), True) write_package(NOTIFICATIONS, 'Notification', 'Receiver', join(gen_dir, 'lsp-server_notification_receivers.ads'), False) if __name__ == '__main__': write_message_types() write_handle_request() write_server_handlers() write_server_receivers()