diff --git a/src/ServiceHost/LanguageSupport/AutoCompleteService.cs b/src/ServiceHost/LanguageSupport/AutoCompleteService.cs
deleted file mode 100644
index 2cf98484..00000000
--- a/src/ServiceHost/LanguageSupport/AutoCompleteService.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using Microsoft.SqlTools.EditorServices.Connection;
-using Microsoft.SqlTools.EditorServices.Protocol.LanguageServer;
-using System;
-using System.Collections.Generic;
-
-namespace Microsoft.SqlTools.LanguageSupport
-{
- ///
- /// Main class for Autocomplete functionality
- ///
- public class AutoCompleteService
- {
- ///
- /// Singleton service instance
- ///
- private static Lazy instance
- = new Lazy(() => new AutoCompleteService());
-
- ///
- /// The current autocomplete candidate list
- ///
- private IEnumerable autoCompleteList;
-
- ///
- /// Gets the current autocomplete candidate list
- ///
- public IEnumerable AutoCompleteList
- {
- get
- {
- return this.autoCompleteList;
- }
- }
-
- ///
- /// Gets the singleton service instance
- ///
- public static AutoCompleteService Instance
- {
- get
- {
- return instance.Value;
- }
- }
-
- ///
- /// Update the cached autocomplete candidate list when the user connects to a database
- ///
- ///
- public void UpdateAutoCompleteCache(ISqlConnection connection)
- {
- this.autoCompleteList = connection.GetServerObjects();
- }
-
- ///
- /// Return the completion item list for the current text position
- ///
- ///
- public CompletionItem[] GetCompletionItems(TextDocumentPosition textDocumentPosition)
- {
- var completions = new List();
-
- int i = 0;
-
- // the completion list will be null is user not connected to server
- if (this.AutoCompleteList != null)
- {
- foreach (var autoCompleteItem in this.AutoCompleteList)
- {
- // convert the completion item candidates into CompletionItems
- completions.Add(new CompletionItem()
- {
- Label = autoCompleteItem,
- Kind = CompletionItemKind.Keyword,
- Detail = autoCompleteItem + " details",
- Documentation = autoCompleteItem + " documentation",
- TextEdit = new TextEdit
- {
- NewText = autoCompleteItem,
- Range = new Range
- {
- Start = new Position
- {
- Line = textDocumentPosition.Position.Line,
- Character = textDocumentPosition.Position.Character
- },
- End = new Position
- {
- Line = textDocumentPosition.Position.Line,
- Character = textDocumentPosition.Position.Character + 5
- }
- }
- }
- });
-
- // only show 50 items
- if (++i == 50)
- {
- break;
- }
- }
- }
- return completions.ToArray();
- }
-
- }
-}
diff --git a/src/ServiceHost/LanguageSupport/LanguageService.cs b/src/ServiceHost/LanguageSupport/LanguageService.cs
deleted file mode 100644
index ff4f4a65..00000000
--- a/src/ServiceHost/LanguageSupport/LanguageService.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using Microsoft.SqlTools.EditorServices;
-using Microsoft.SqlTools.EditorServices.Session;
-using Microsoft.SqlServer.Management.SqlParser.Parser;
-using System.Collections.Generic;
-
-namespace Microsoft.SqlTools.LanguageSupport
-{
- ///
- /// Main class for Language Service functionality
- ///
- public class LanguageService
- {
- ///
- /// The cached parse result from previous incremental parse
- ///
- private ParseResult prevParseResult;
-
- ///
- /// Gets or sets the current SQL Tools context
- ///
- ///
- private SqlToolsContext Context { get; set; }
-
- ///
- /// Constructor for the Language Service class
- ///
- ///
- public LanguageService(SqlToolsContext context)
- {
- this.Context = context;
- }
-
- ///
- /// Gets a list of semantic diagnostic marks for the provided script file
- ///
- ///
- public ScriptFileMarker[] GetSemanticMarkers(ScriptFile scriptFile)
- {
- // parse current SQL file contents to retrieve a list of errors
- ParseOptions parseOptions = new ParseOptions();
- ParseResult parseResult = Parser.IncrementalParse(
- scriptFile.Contents,
- prevParseResult,
- parseOptions);
-
- // save previous result for next incremental parse
- this.prevParseResult = parseResult;
-
- // build a list of SQL script file markers from the errors
- List markers = new List();
- foreach (var error in parseResult.Errors)
- {
- markers.Add(new ScriptFileMarker()
- {
- Message = error.Message,
- Level = ScriptFileMarkerLevel.Error,
- ScriptRegion = new ScriptRegion()
- {
- File = scriptFile.FilePath,
- StartLineNumber = error.Start.LineNumber,
- StartColumnNumber = error.Start.ColumnNumber,
- StartOffset = 0,
- EndLineNumber = error.End.LineNumber,
- EndColumnNumber = error.End.ColumnNumber,
- EndOffset = 0
- }
- });
- }
-
- return markers.ToArray();
- }
- }
-}
diff --git a/src/ServiceHost/Server/LanguageServer.cs b/src/ServiceHost/Server/LanguageServer.cs
deleted file mode 100644
index c2952f92..00000000
--- a/src/ServiceHost/Server/LanguageServer.cs
+++ /dev/null
@@ -1,583 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-using Microsoft.SqlTools.EditorServices.Protocol.LanguageServer;
-using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
-using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel;
-using Microsoft.SqlTools.EditorServices.Session;
-using System.Threading.Tasks;
-using Microsoft.SqlTools.EditorServices.Utility;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Linq;
-using System;
-using Microsoft.SqlTools.EditorServices.Connection;
-using Microsoft.SqlTools.LanguageSupport;
-
-namespace Microsoft.SqlTools.EditorServices.Protocol.Server
-{
- ///
- /// SQL Tools VS Code Language Server request handler
- ///
- public class LanguageServer : LanguageServerBase
- {
- private static CancellationTokenSource existingRequestCancellation;
-
- private LanguageServerSettings currentSettings = new LanguageServerSettings();
-
- private EditorSession editorSession;
-
- ///
- /// Provides details about the host application.
- ///
- public LanguageServer(HostDetails hostDetails, ProfilePaths profilePaths)
- : base(new StdioServerChannel())
- {
- this.editorSession = new EditorSession();
- this.editorSession.StartSession(hostDetails, profilePaths);
- }
-
- ///
- /// Initialize the VS Code request/response callbacks
- ///
- protected override void Initialize()
- {
- // Register all supported message types
- this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
- this.SetEventHandler(DidChangeTextDocumentNotification.Type, this.HandleDidChangeTextDocumentNotification);
- this.SetEventHandler(DidOpenTextDocumentNotification.Type, this.HandleDidOpenTextDocumentNotification);
- this.SetEventHandler(DidCloseTextDocumentNotification.Type, this.HandleDidCloseTextDocumentNotification);
- this.SetEventHandler(DidChangeConfigurationNotification.Type, this.HandleDidChangeConfigurationNotification);
-
- this.SetRequestHandler(DefinitionRequest.Type, this.HandleDefinitionRequest);
- this.SetRequestHandler(ReferencesRequest.Type, this.HandleReferencesRequest);
- this.SetRequestHandler(CompletionRequest.Type, this.HandleCompletionRequest);
- this.SetRequestHandler(CompletionResolveRequest.Type, this.HandleCompletionResolveRequest);
- this.SetRequestHandler(SignatureHelpRequest.Type, this.HandleSignatureHelpRequest);
- this.SetRequestHandler(DocumentHighlightRequest.Type, this.HandleDocumentHighlightRequest);
- this.SetRequestHandler(HoverRequest.Type, this.HandleHoverRequest);
- this.SetRequestHandler(DocumentSymbolRequest.Type, this.HandleDocumentSymbolRequest);
- this.SetRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest);
-
- this.SetRequestHandler(ConnectionRequest.Type, this.HandleConnectRequest);
-
- // register an OnConnection callback
- ConnectionService.Instance.RegisterOnConnectionTask(OnConnection);
- }
-
- ///
- /// Callback for when a user connection is done processing
- ///
- ///
- public Task OnConnection(ISqlConnection sqlConnection)
- {
- AutoCompleteService.Instance.UpdateAutoCompleteCache(sqlConnection);
- return Task.FromResult(true);
- }
-
- ///
- /// Handles the shutdown event for the Language Server
- ///
- protected override async Task Shutdown()
- {
- Logger.Write(LogLevel.Normal, "Language service is shutting down...");
-
- if (this.editorSession != null)
- {
- this.editorSession.Dispose();
- this.editorSession = null;
- }
-
- await Task.FromResult(true);
- }
-
- ///
- /// Handles the initialization request
- ///
- ///
- ///
- ///
- protected async Task HandleInitializeRequest(
- InitializeRequest initializeParams,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDidChangeTextDocumentNotification");
-
- // Grab the workspace path from the parameters
- editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
-
- await requestContext.SendResult(
- new InitializeResult
- {
- Capabilities = new ServerCapabilities
- {
- TextDocumentSync = TextDocumentSyncKind.Incremental,
- DefinitionProvider = true,
- ReferencesProvider = true,
- DocumentHighlightProvider = true,
- DocumentSymbolProvider = true,
- WorkspaceSymbolProvider = true,
- HoverProvider = true,
- CompletionProvider = new CompletionOptions
- {
- ResolveProvider = true,
- TriggerCharacters = new string[] { ".", "-", ":", "\\" }
- },
- SignatureHelpProvider = new SignatureHelpOptions
- {
- TriggerCharacters = new string[] { " " } // TODO: Other characters here?
- }
- }
- });
- }
-
- ///
- /// Handles text document change events
- ///
- ///
- ///
- ///
- protected async Task HandleDidChangeTextDocumentNotification(
- DidChangeTextDocumentParams textChangeParams,
- EventContext eventContext)
- {
- StringBuilder msg = new StringBuilder();
- msg.Append("HandleDidChangeTextDocumentNotification");
- List changedFiles = new List();
-
- // A text change notification can batch multiple change requests
- foreach (var textChange in textChangeParams.ContentChanges)
- {
- string fileUri = textChangeParams.Uri ?? textChangeParams.TextDocument.Uri;
- msg.AppendLine();
- msg.Append(" File: ");
- msg.Append(fileUri);
-
- ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri);
-
- changedFile.ApplyChange(
- GetFileChangeDetails(
- textChange.Range.Value,
- textChange.Text));
-
- changedFiles.Add(changedFile);
- }
-
- Logger.Write(LogLevel.Verbose, msg.ToString());
-
- await this.RunScriptDiagnostics(
- changedFiles.ToArray(),
- editorSession,
- eventContext);
-
- await Task.FromResult(true);
- }
-
- ///
- /// Handle the file open notification
- ///
- ///
- ///
- protected Task HandleDidOpenTextDocumentNotification(
- DidOpenTextDocumentNotification openParams,
- EventContext eventContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDidOpenTextDocumentNotification");
-
- // read the SQL file contents into the ScriptFile
- ScriptFile openedFile =
- editorSession.Workspace.GetFileBuffer(
- openParams.Uri,
- openParams.Text);
-
- // run diagnostics on the opened file
- this.RunScriptDiagnostics(
- new ScriptFile[] { openedFile },
- editorSession,
- eventContext);
-
- return Task.FromResult(true);
- }
-
- ///
- /// Handle the close document notication
- ///
- ///
- ///
- protected Task HandleDidCloseTextDocumentNotification(
- TextDocumentIdentifier closeParams,
- EventContext eventContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDidCloseTextDocumentNotification");
- return Task.FromResult(true);
- }
-
- ///
- /// Handles the configuration change event
- ///
- ///
- ///
- protected async Task HandleDidChangeConfigurationNotification(
- DidChangeConfigurationParams configChangeParams,
- EventContext eventContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDidChangeConfigurationNotification");
-
- bool oldLoadProfiles = this.currentSettings.EnableProfileLoading;
- bool oldScriptAnalysisEnabled =
- this.currentSettings.ScriptAnalysis.Enable.HasValue;
- string oldScriptAnalysisSettingsPath =
- this.currentSettings.ScriptAnalysis.SettingsPath;
-
- this.currentSettings.Update(
- configChangeParams.Settings.SqlTools,
- this.editorSession.Workspace.WorkspacePath);
-
- // If script analysis settings have changed we need to clear & possibly update the current diagnostic records.
- if ((oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable))
- {
- // If the user just turned off script analysis or changed the settings path, send a diagnostics
- // event to clear the analysis markers that they already have.
- if (!this.currentSettings.ScriptAnalysis.Enable.Value)
- {
- ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];
-
- foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
- {
- await PublishScriptDiagnostics(
- scriptFile,
- emptyAnalysisDiagnostics,
- eventContext);
- }
- }
- else
- {
- await this.RunScriptDiagnostics(
- this.editorSession.Workspace.GetOpenedFiles(),
- this.editorSession,
- eventContext);
- }
- }
-
- await Task.FromResult(true);
- }
-
- protected async Task HandleDefinitionRequest(
- TextDocumentPosition textDocumentPosition,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDefinitionRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleReferencesRequest(
- ReferencesParams referencesParams,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleReferencesRequest");
- await Task.FromResult(true);
- }
-
- ///
- /// Handles the completion list request
- ///
- ///
- ///
- protected async Task HandleCompletionRequest(
- TextDocumentPosition textDocumentPosition,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleCompletionRequest");
-
- // get teh current list of completion items and return to client
- var completionItems = AutoCompleteService.Instance.GetCompletionItems(textDocumentPosition);
- await requestContext.SendResult(completionItems);
- }
-
- protected async Task HandleCompletionResolveRequest(
- CompletionItem completionItem,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleCompletionResolveRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleSignatureHelpRequest(
- TextDocumentPosition textDocumentPosition,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleSignatureHelpRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleDocumentHighlightRequest(
- TextDocumentPosition textDocumentPosition,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDocumentHighlightRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleHoverRequest(
- TextDocumentPosition textDocumentPosition,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleHoverRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleDocumentSymbolRequest(
- TextDocumentIdentifier textDocumentIdentifier,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleDocumentSymbolRequest");
- await Task.FromResult(true);
- }
-
- protected async Task HandleWorkspaceSymbolRequest(
- WorkspaceSymbolParams workspaceSymbolParams,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleWorkspaceSymbolRequest");
- await Task.FromResult(true);
- }
-
- ///
- /// Handle new connection requests
- ///
- ///
- ///
- ///
- protected async Task HandleConnectRequest(
- ConnectionDetails connectionDetails,
- RequestContext requestContext)
- {
- Logger.Write(LogLevel.Verbose, "HandleConnectRequest");
-
- // open connection base on request details
- ConnectionResult result = ConnectionService.Instance.Connect(connectionDetails);
-
- await requestContext.SendResult(result);
- }
-
- ///
- /// Runs script diagnostics on changed files
- ///
- ///
- ///
- ///
- private Task RunScriptDiagnostics(
- ScriptFile[] filesToAnalyze,
- EditorSession editorSession,
- EventContext eventContext)
- {
- if (!this.currentSettings.ScriptAnalysis.Enable.Value)
- {
- // If the user has disabled script analysis, skip it entirely
- return Task.FromResult(true);
- }
-
- // If there's an existing task, attempt to cancel it
- try
- {
- if (existingRequestCancellation != null)
- {
- // Try to cancel the request
- existingRequestCancellation.Cancel();
-
- // If cancellation didn't throw an exception,
- // clean up the existing token
- existingRequestCancellation.Dispose();
- existingRequestCancellation = null;
- }
- }
- catch (Exception e)
- {
- Logger.Write(
- LogLevel.Error,
- string.Format(
- "Exception while cancelling analysis task:\n\n{0}",
- e.ToString()));
-
- TaskCompletionSource cancelTask = new TaskCompletionSource();
- cancelTask.SetCanceled();
- return cancelTask.Task;
- }
-
- // Create a fresh cancellation token and then start the task.
- // We create this on a different TaskScheduler so that we
- // don't block the main message loop thread.
- existingRequestCancellation = new CancellationTokenSource();
- Task.Factory.StartNew(
- () =>
- DelayThenInvokeDiagnostics(
- 750,
- filesToAnalyze,
- editorSession,
- eventContext,
- existingRequestCancellation.Token),
- CancellationToken.None,
- TaskCreationOptions.None,
- TaskScheduler.Default);
-
- return Task.FromResult(true);
- }
-
- ///
- /// Actually run the script diagnostics after waiting for some small delay
- ///
- ///
- ///
- ///
- ///
- ///
- private static async Task DelayThenInvokeDiagnostics(
- int delayMilliseconds,
- ScriptFile[] filesToAnalyze,
- EditorSession editorSession,
- EventContext eventContext,
- CancellationToken cancellationToken)
- {
- // First of all, wait for the desired delay period before
- // analyzing the provided list of files
- try
- {
- await Task.Delay(delayMilliseconds, cancellationToken);
- }
- catch (TaskCanceledException)
- {
- // If the task is cancelled, exit directly
- return;
- }
-
- // If we've made it past the delay period then we don't care
- // about the cancellation token anymore. This could happen
- // when the user stops typing for long enough that the delay
- // period ends but then starts typing while analysis is going
- // on. It makes sense to send back the results from the first
- // delay period while the second one is ticking away.
-
- // Get the requested files
- foreach (ScriptFile scriptFile in filesToAnalyze)
- {
- ScriptFileMarker[] semanticMarkers = null;
- if (editorSession.LanguageService != null)
- {
- Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);
- semanticMarkers = editorSession.LanguageService.GetSemanticMarkers(scriptFile);
- Logger.Write(LogLevel.Verbose, "Analysis complete.");
- }
- else
- {
- // Semantic markers aren't available if the AnalysisService
- // isn't available
- semanticMarkers = new ScriptFileMarker[0];
- }
-
- await PublishScriptDiagnostics(
- scriptFile,
- semanticMarkers,
- eventContext);
- }
- }
-
- ///
- /// Send the diagnostic results back to the host application
- ///
- ///
- ///
- ///
- private static async Task PublishScriptDiagnostics(
- ScriptFile scriptFile,
- ScriptFileMarker[] semanticMarkers,
- EventContext eventContext)
- {
- var allMarkers = scriptFile.SyntaxMarkers != null
- ? scriptFile.SyntaxMarkers.Concat(semanticMarkers)
- : semanticMarkers;
-
- // Always send syntax and semantic errors. We want to
- // make sure no out-of-date markers are being displayed.
- await eventContext.SendEvent(
- PublishDiagnosticsNotification.Type,
- new PublishDiagnosticsNotification
- {
- Uri = scriptFile.ClientFilePath,
- Diagnostics =
- allMarkers
- .Select(GetDiagnosticFromMarker)
- .ToArray()
- });
- }
-
- ///
- /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible
- ///
- ///
- ///
- private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
- {
- return new Diagnostic
- {
- Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
- Message = scriptFileMarker.Message,
- Range = new Range
- {
- // TODO: What offsets should I use?
- Start = new Position
- {
- Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
- Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
- },
- End = new Position
- {
- Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
- Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
- }
- }
- };
- }
-
- ///
- /// Map ScriptFileMarker severity to Diagnostic severity
- ///
- ///
- private static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel markerLevel)
- {
- switch (markerLevel)
- {
- case ScriptFileMarkerLevel.Error:
- return DiagnosticSeverity.Error;
-
- case ScriptFileMarkerLevel.Warning:
- return DiagnosticSeverity.Warning;
-
- case ScriptFileMarkerLevel.Information:
- return DiagnosticSeverity.Information;
-
- default:
- return DiagnosticSeverity.Error;
- }
- }
-
- ///
- /// Switch from 0-based offsets to 1 based offsets
- ///
- ///
- ///
- private static FileChange GetFileChangeDetails(Range changeRange, string insertString)
- {
- // The protocol's positions are zero-based so add 1 to all offsets
- return new FileChange
- {
- InsertString = insertString,
- Line = changeRange.Start.Line + 1,
- Offset = changeRange.Start.Character + 1,
- EndLine = changeRange.End.Line + 1,
- EndOffset = changeRange.End.Character + 1
- };
- }
- }
-}
diff --git a/test/ServiceHost.Test/Utility/TestObjects.cs b/test/ServiceHost.Test/Utility/TestObjects.cs
index 4e086279..c506d600 100644
--- a/test/ServiceHost.Test/Utility/TestObjects.cs
+++ b/test/ServiceHost.Test/Utility/TestObjects.cs
@@ -53,7 +53,7 @@ namespace Microsoft.SqlTools.Test.Utility
///
public static LanguageService GetTestLanguageService()
{
- return new LanguageService(new SqlToolsContext(null, null));
+ return new LanguageService();
}
///