diff --git a/src/ServiceHost/Hosting/ServiceHost.cs b/src/ServiceHost/Hosting/ServiceHost.cs index dbc561fe..0f2a0d9a 100644 --- a/src/ServiceHost/Hosting/ServiceHost.cs +++ b/src/ServiceHost/Hosting/ServiceHost.cs @@ -45,7 +45,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting // Initialize the shutdown activities shutdownCallbacks = new List(); initializeCallbacks = new List(); + } + /// + /// Provide initialization that must occur after the service host is started + /// + public void Initialize() + { // Register the requests that this service host will handle this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest); this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest); diff --git a/src/ServiceHost/LanguageServices/LanguageService.cs b/src/ServiceHost/LanguageServices/LanguageService.cs index d40aa5fc..eb643c0c 100644 --- a/src/ServiceHost/LanguageServices/LanguageService.cs +++ b/src/ServiceHost/LanguageServices/LanguageService.cs @@ -17,6 +17,7 @@ using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts; using System.Linq; using Microsoft.SqlServer.Management.SqlParser.Parser; using Location = Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts.Location; +using Microsoft.SqlTools.ServiceLayer.Connection; namespace Microsoft.SqlTools.ServiceLayer.LanguageServices { @@ -38,9 +39,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices /// /// Default, parameterless constructor. - /// TODO: Figure out how to make this truely singleton even with dependency injection for tests /// - public LanguageService() + internal LanguageService() { } @@ -98,6 +98,15 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices // Register the configuration update handler WorkspaceService.Instance.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification); + // Register the file change update handler + WorkspaceService.Instance.RegisterTextDocChangeCallback(HandleDidChangeTextDocumentNotification); + + // Register the file open update handler + WorkspaceService.Instance.RegisterTextDocOpenCallback(HandleDidOpenTextDocumentNotification); + + // register an OnConnection callback + ConnectionService.Instance.RegisterOnConnectionTask(OnConnection); + // Store the SqlToolsContext for future use Context = context; } @@ -166,8 +175,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Verbose, "HandleCompletionRequest"); - await Task.FromResult(true); + Logger.Write(LogLevel.Verbose, "HandleCompletionRequest"); + + // get the current list of completion items and return to client + var completionItems = AutoCompleteService.Instance.GetCompletionItems(textDocumentPosition); + await requestContext.SendResult(completionItems); } private static async Task HandleCompletionResolveRequest( @@ -222,6 +234,45 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices #region Handlers for Events from Other Services + /// + /// Handle the file open notification + /// + /// + /// + /// + public async Task HandleDidOpenTextDocumentNotification( + ScriptFile scriptFile, + EventContext eventContext) + { + await this.RunScriptDiagnostics( + new ScriptFile[] { scriptFile }, + eventContext); + + await Task.FromResult(true); + } + + + /// + /// Handles text document change events + /// + /// + /// + /// + public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext) + { + await this.RunScriptDiagnostics( + changedFiles.ToArray(), + eventContext); + + await Task.FromResult(true); + } + + /// + /// Handle the file configuration change notification + /// + /// + /// + /// public async Task HandleDidChangeConfigurationNotification( SqlToolsSettings newSettings, SqlToolsSettings oldSettings, @@ -252,7 +303,17 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices CurrentSettings.EnableProfileLoading = newSettings.EnableProfileLoading; CurrentSettings.ScriptAnalysis.Update(newSettings.ScriptAnalysis, CurrentWorkspace.WorkspacePath); } - + + /// + /// Callback for when a user connection is done processing + /// + /// + public async Task OnConnection(ISqlConnection sqlConnection) + { + await AutoCompleteService.Instance.UpdateAutoCompleteCache(sqlConnection); + await Task.FromResult(true); + } + #endregion #region Private Helpers diff --git a/src/ServiceHost/Program.cs b/src/ServiceHost/Program.cs index 02369811..a3f9cf8b 100644 --- a/src/ServiceHost/Program.cs +++ b/src/ServiceHost/Program.cs @@ -7,6 +7,7 @@ using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.WorkspaceServices; using Microsoft.SqlTools.ServiceLayer.LanguageServices; +using Microsoft.SqlTools.ServiceLayer.Connection; namespace Microsoft.SqlTools.ServiceLayer { @@ -37,13 +38,16 @@ namespace Microsoft.SqlTools.ServiceLayer // Grab the instance of the service host ServiceHost serviceHost = ServiceHost.Instance; + // Start the service + serviceHost.Start().Wait(); + // Initialize the services that will be hosted here WorkspaceService.Instance.InitializeService(serviceHost); AutoCompleteService.Instance.InitializeService(serviceHost); LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext); + ConnectionService.Instance.Initialize(serviceHost); - // Start the service - serviceHost.Start().Wait(); + serviceHost.Initialize(); serviceHost.WaitForExit(); } } diff --git a/src/ServiceHost/Properties/AssemblyInfo.cs b/src/ServiceHost/Properties/AssemblyInfo.cs index 27c1daba..ee34cfc1 100644 --- a/src/ServiceHost/Properties/AssemblyInfo.cs +++ b/src/ServiceHost/Properties/AssemblyInfo.cs @@ -41,4 +41,4 @@ using System.Runtime.InteropServices; [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0.0")] -[assembly: InternalsVisibleTo("Microsoft.SqlTools.EditorServices.Test.Protocol")] +[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceHost.Test")] diff --git a/src/ServiceHost/WorkspaceServices/WorkspaceService.cs b/src/ServiceHost/WorkspaceServices/WorkspaceService.cs index 13575121..96878f45 100644 --- a/src/ServiceHost/WorkspaceServices/WorkspaceService.cs +++ b/src/ServiceHost/WorkspaceServices/WorkspaceService.cs @@ -43,6 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices { ConfigChangeCallbacks = new List(); TextDocChangeCallbacks = new List(); + TextDocOpenCallbacks = new List(); } #endregion @@ -69,6 +70,13 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices /// Context of the event raised for the changed files public delegate Task TextDocChangeCallback(ScriptFile[] changedFiles, EventContext eventContext); + /// + /// Delegate for callbacks that occur when a text document is opened + /// + /// File that was opened + /// Context of the event raised for the changed files + public delegate Task TextDocOpenCallback(ScriptFile openFile, EventContext eventContext); + /// /// List of callbacks to call when the configuration of the workspace changes /// @@ -79,6 +87,12 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices /// private List TextDocChangeCallbacks { get; set; } + /// + /// List of callbacks to call when a text document is opened + /// + private List TextDocOpenCallbacks { get; set; } + + #endregion #region Public Methods @@ -140,6 +154,15 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices TextDocChangeCallbacks.Add(task); } + /// + /// Adds a new task to be called when a file is opened + /// + /// Delegate to call when a document is opened + public void RegisterTextDocOpenCallback(TextDocOpenCallback task) + { + TextDocOpenCallbacks.Add(task); + } + #endregion #region Event Handlers @@ -158,7 +181,7 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices // A text change notification can batch multiple change requests foreach (var textChange in textChangeParams.ContentChanges) { - string fileUri = textChangeParams.TextDocument.Uri; + string fileUri = textChangeParams.Uri ?? textChangeParams.TextDocument.Uri; msg.AppendLine(String.Format(" File: {0}", fileUri)); ScriptFile changedFile = Workspace.GetFile(fileUri); @@ -177,12 +200,20 @@ namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices return Task.WhenAll(handlers); } - protected Task HandleDidOpenTextDocumentNotification( + protected async Task HandleDidOpenTextDocumentNotification( DidOpenTextDocumentNotification openParams, EventContext eventContext) { Logger.Write(LogLevel.Verbose, "HandleDidOpenTextDocumentNotification"); - return Task.FromResult(true); + + // read the SQL file contents into the ScriptFile + ScriptFile openedFile = Workspace.GetFileBuffer(openParams.Uri, openParams.Text); + + // Propagate the changes to the event handlers + var textDocOpenTasks = TextDocOpenCallbacks.Select( + t => t(openedFile, eventContext)); + + await Task.WhenAll(textDocOpenTasks); } protected Task HandleDidCloseTextDocumentNotification( diff --git a/src/ServiceHost/project.json b/src/ServiceHost/project.json index 31dac66d..bd889b55 100644 --- a/src/ServiceHost/project.json +++ b/src/ServiceHost/project.json @@ -1,4 +1,5 @@ { + "name": "Microsoft.SqlTools.ServiceHost", "version": "1.0.0-*", "buildOptions": { "debugType": "portable", diff --git a/test/ServiceHost.Test/project.json b/test/ServiceHost.Test/project.json index a248b200..a32fe523 100644 --- a/test/ServiceHost.Test/project.json +++ b/test/ServiceHost.Test/project.json @@ -1,4 +1,5 @@ { + "name": "Microsoft.SqlTools.ServiceHost.Test", "version": "1.0.0-*", "buildOptions": { "debugType": "portable"