From f2bb986f427124d4d1d85bbd36e1999e84eb946e Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Fri, 15 Jul 2016 23:22:27 -0700 Subject: [PATCH 1/4] Remove unneeded files and clean up remaining code. --- ServiceHost/.vscode/launch.json | 4 +- ServiceHost/Client/DebugAdapterClientBase.cs | 48 - ServiceHost/Client/LanguageClientBase.cs | 44 - ServiceHost/Client/LanguageServiceClient.cs | 121 -- ServiceHost/DebugAdapter/AttachRequest.cs | 23 - ServiceHost/DebugAdapter/Breakpoint.cs | 81 -- .../DebugAdapter/ConfigurationDoneRequest.cs | 16 - ServiceHost/DebugAdapter/ContinueRequest.cs | 17 - ServiceHost/DebugAdapter/DisconnectRequest.cs | 17 - ServiceHost/DebugAdapter/EvaluateRequest.cs | 53 - ServiceHost/DebugAdapter/ExitedEvent.cs | 22 - ServiceHost/DebugAdapter/InitializeRequest.cs | 56 - ServiceHost/DebugAdapter/InitializedEvent.cs | 16 - ServiceHost/DebugAdapter/LaunchRequest.cs | 66 - ServiceHost/DebugAdapter/NextRequest.cs | 20 - ServiceHost/DebugAdapter/OutputEvent.cs | 24 - ServiceHost/DebugAdapter/PauseRequest.cs | 17 - ServiceHost/DebugAdapter/Scope.cs | 40 - ServiceHost/DebugAdapter/ScopesRequest.cs | 29 - .../DebugAdapter/SetBreakpointsRequest.cs | 43 - .../SetExceptionBreakpointsRequest.cs | 31 - .../SetFunctionBreakpointsRequest.cs | 31 - ServiceHost/DebugAdapter/Source.cs | 17 - ServiceHost/DebugAdapter/SourceRequest.cs | 29 - ServiceHost/DebugAdapter/StackFrame.cs | 53 - ServiceHost/DebugAdapter/StackTraceRequest.cs | 33 - ServiceHost/DebugAdapter/StartedEvent.cs | 16 - ServiceHost/DebugAdapter/StepInRequest.cs | 17 - ServiceHost/DebugAdapter/StepOutRequest.cs | 16 - ServiceHost/DebugAdapter/StoppedEvent.cs | 41 - ServiceHost/DebugAdapter/TerminatedEvent.cs | 17 - ServiceHost/DebugAdapter/Thread.cs | 15 - ServiceHost/DebugAdapter/ThreadsRequest.cs | 22 - ServiceHost/DebugAdapter/Variable.cs | 33 - ServiceHost/DebugAdapter/VariablesRequest.cs | 29 - .../LanguageServer/ClientCapabilities.cs | 5 - ServiceHost/LanguageServer/Completion.cs | 1 - ServiceHost/LanguageServer/Diagnostics.cs | 5 - ServiceHost/LanguageServer/EditorCommands.cs | 111 -- ServiceHost/LanguageServer/Hover.cs | 5 - .../Channel/NamedPipeClientChannel.cs | 83 -- .../Channel/NamedPipeServerChannel.cs | 65 - .../Channel/StdioClientChannel.cs | 2 - .../Channel/StdioServerChannel.cs | 2 - ServiceHost/Messages/PromptEvents.cs | 58 - ServiceHost/Properties/AssemblyInfo.cs | 8 +- ServiceHost/Server/DebugAdapter.cs | 584 -------- ServiceHost/Server/DebugAdapterBase.cs | 73 - ServiceHost/Server/LanguageServer.cs | 1183 +---------------- ServiceHost/Server/LanguageServerSettings.cs | 2 + ServiceHost/Server/OutputDebouncer.cs | 102 -- ServiceHost/Server/PromptHandlers.cs | 190 --- ServiceHost/Utility/AsyncDebouncer.cs | 169 --- 53 files changed, 63 insertions(+), 3742 deletions(-) delete mode 100644 ServiceHost/Client/DebugAdapterClientBase.cs delete mode 100644 ServiceHost/Client/LanguageClientBase.cs delete mode 100644 ServiceHost/Client/LanguageServiceClient.cs delete mode 100644 ServiceHost/DebugAdapter/AttachRequest.cs delete mode 100644 ServiceHost/DebugAdapter/Breakpoint.cs delete mode 100644 ServiceHost/DebugAdapter/ConfigurationDoneRequest.cs delete mode 100644 ServiceHost/DebugAdapter/ContinueRequest.cs delete mode 100644 ServiceHost/DebugAdapter/DisconnectRequest.cs delete mode 100644 ServiceHost/DebugAdapter/EvaluateRequest.cs delete mode 100644 ServiceHost/DebugAdapter/ExitedEvent.cs delete mode 100644 ServiceHost/DebugAdapter/InitializeRequest.cs delete mode 100644 ServiceHost/DebugAdapter/InitializedEvent.cs delete mode 100644 ServiceHost/DebugAdapter/LaunchRequest.cs delete mode 100644 ServiceHost/DebugAdapter/NextRequest.cs delete mode 100644 ServiceHost/DebugAdapter/OutputEvent.cs delete mode 100644 ServiceHost/DebugAdapter/PauseRequest.cs delete mode 100644 ServiceHost/DebugAdapter/Scope.cs delete mode 100644 ServiceHost/DebugAdapter/ScopesRequest.cs delete mode 100644 ServiceHost/DebugAdapter/SetBreakpointsRequest.cs delete mode 100644 ServiceHost/DebugAdapter/SetExceptionBreakpointsRequest.cs delete mode 100644 ServiceHost/DebugAdapter/SetFunctionBreakpointsRequest.cs delete mode 100644 ServiceHost/DebugAdapter/Source.cs delete mode 100644 ServiceHost/DebugAdapter/SourceRequest.cs delete mode 100644 ServiceHost/DebugAdapter/StackFrame.cs delete mode 100644 ServiceHost/DebugAdapter/StackTraceRequest.cs delete mode 100644 ServiceHost/DebugAdapter/StartedEvent.cs delete mode 100644 ServiceHost/DebugAdapter/StepInRequest.cs delete mode 100644 ServiceHost/DebugAdapter/StepOutRequest.cs delete mode 100644 ServiceHost/DebugAdapter/StoppedEvent.cs delete mode 100644 ServiceHost/DebugAdapter/TerminatedEvent.cs delete mode 100644 ServiceHost/DebugAdapter/Thread.cs delete mode 100644 ServiceHost/DebugAdapter/ThreadsRequest.cs delete mode 100644 ServiceHost/DebugAdapter/Variable.cs delete mode 100644 ServiceHost/DebugAdapter/VariablesRequest.cs delete mode 100644 ServiceHost/LanguageServer/EditorCommands.cs delete mode 100644 ServiceHost/MessageProtocol/Channel/NamedPipeClientChannel.cs delete mode 100644 ServiceHost/MessageProtocol/Channel/NamedPipeServerChannel.cs delete mode 100644 ServiceHost/Messages/PromptEvents.cs delete mode 100644 ServiceHost/Server/DebugAdapter.cs delete mode 100644 ServiceHost/Server/DebugAdapterBase.cs delete mode 100644 ServiceHost/Server/OutputDebouncer.cs delete mode 100644 ServiceHost/Server/PromptHandlers.cs delete mode 100644 ServiceHost/Utility/AsyncDebouncer.cs diff --git a/ServiceHost/.vscode/launch.json b/ServiceHost/.vscode/launch.json index 51cdc900..ea4209f7 100644 --- a/ServiceHost/.vscode/launch.json +++ b/ServiceHost/.vscode/launch.json @@ -10,13 +10,15 @@ "args": [], "cwd": "${workspaceRoot}", "externalConsole": true, + "requireExactSource": false, "stopAtEntry": false }, { "name": ".NET Core Attach", "type": "coreclr", "request": "attach", - "processId": 16900 + "requireExactSource": false, + "processId": 14720 } ] } \ No newline at end of file diff --git a/ServiceHost/Client/DebugAdapterClientBase.cs b/ServiceHost/Client/DebugAdapterClientBase.cs deleted file mode 100644 index e2949307..00000000 --- a/ServiceHost/Client/DebugAdapterClientBase.cs +++ /dev/null @@ -1,48 +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.DebugAdapter; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Client -{ - public class DebugAdapterClient : ProtocolEndpoint - { - public DebugAdapterClient(ChannelBase clientChannel) - : base(clientChannel, MessageProtocolType.DebugAdapter) - { - } - - public async Task LaunchScript(string scriptFilePath) - { - await this.SendRequest( - LaunchRequest.Type, - new LaunchRequestArguments { - Program = scriptFilePath - }); - - await this.SendRequest(ConfigurationDoneRequest.Type, null); - } - - protected override Task OnStart() - { - return Task.FromResult(true); - } - - protected override Task OnConnect() - { - // Initialize the debug adapter - return this.SendRequest( - InitializeRequest.Type, - new InitializeRequestArguments - { - LinesStartAt1 = true - }); - } - } -} - diff --git a/ServiceHost/Client/LanguageClientBase.cs b/ServiceHost/Client/LanguageClientBase.cs deleted file mode 100644 index 22522252..00000000 --- a/ServiceHost/Client/LanguageClientBase.cs +++ /dev/null @@ -1,44 +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 System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Client -{ - /// - /// Provides a base implementation for language server clients. - /// - public abstract class LanguageClientBase : ProtocolEndpoint - { - /// - /// Initializes an instance of the language client using the - /// specified channel for communication. - /// - /// The channel to use for communication with the server. - public LanguageClientBase(ChannelBase clientChannel) - : base(clientChannel, MessageProtocolType.LanguageServer) - { - } - - protected override Task OnStart() - { - // Initialize the implementation class - return this.Initialize(); - } - - protected override async Task OnStop() - { - // First, notify the language server that we're stopping - var response = await this.SendRequest(ShutdownRequest.Type, new object()); - await this.SendEvent(ExitNotification.Type, new object()); - } - - protected abstract Task Initialize(); - } -} - diff --git a/ServiceHost/Client/LanguageServiceClient.cs b/ServiceHost/Client/LanguageServiceClient.cs deleted file mode 100644 index 7ec5fba0..00000000 --- a/ServiceHost/Client/LanguageServiceClient.cs +++ /dev/null @@ -1,121 +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 System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Client -{ - public class LanguageServiceClient : LanguageClientBase - { - private Dictionary cachedDiagnostics = - new Dictionary(); - - public LanguageServiceClient(ChannelBase clientChannel) - : base(clientChannel) - { - } - - protected override Task Initialize() - { - // Add handlers for common events - this.SetEventHandler(PublishDiagnosticsNotification.Type, HandlePublishDiagnosticsEvent); - - return Task.FromResult(true); - } - - protected override Task OnConnect() - { - // Send the 'initialize' request and wait for the response - var initializeRequest = new InitializeRequest - { - RootPath = "", - Capabilities = new ClientCapabilities() - }; - - return this.SendRequest( - InitializeRequest.Type, - initializeRequest); - } - - #region Events - - public event EventHandler DiagnosticsReceived; - - protected void OnDiagnosticsReceived(string filePath) - { - if (this.DiagnosticsReceived != null) - { - this.DiagnosticsReceived(this, filePath); - } - } - - #endregion - - #region Private Methods - - private Task HandlePublishDiagnosticsEvent( - PublishDiagnosticsNotification diagnostics, - EventContext eventContext) - { - string normalizedPath = diagnostics.Uri.ToLower(); - - this.cachedDiagnostics[normalizedPath] = - diagnostics.Diagnostics - .Select(GetMarkerFromDiagnostic) - .ToArray(); - - this.OnDiagnosticsReceived(normalizedPath); - - return Task.FromResult(true); - } - - private static ScriptFileMarker GetMarkerFromDiagnostic(Diagnostic diagnostic) - { - DiagnosticSeverity severity = - diagnostic.Severity.GetValueOrDefault( - DiagnosticSeverity.Error); - - return new ScriptFileMarker - { - Level = MapDiagnosticSeverityToLevel(severity), - Message = diagnostic.Message, - ScriptRegion = new ScriptRegion - { - StartLineNumber = diagnostic.Range.Start.Line + 1, - StartColumnNumber = diagnostic.Range.Start.Character + 1, - EndLineNumber = diagnostic.Range.End.Line + 1, - EndColumnNumber = diagnostic.Range.End.Character + 1 - } - }; - } - - private static ScriptFileMarkerLevel MapDiagnosticSeverityToLevel(DiagnosticSeverity severity) - { - switch (severity) - { - case DiagnosticSeverity.Hint: - case DiagnosticSeverity.Information: - return ScriptFileMarkerLevel.Information; - - case DiagnosticSeverity.Warning: - return ScriptFileMarkerLevel.Warning; - - case DiagnosticSeverity.Error: - return ScriptFileMarkerLevel.Error; - - default: - return ScriptFileMarkerLevel.Error; - } - } - - #endregion - } -} diff --git a/ServiceHost/DebugAdapter/AttachRequest.cs b/ServiceHost/DebugAdapter/AttachRequest.cs deleted file mode 100644 index 49fdc5b2..00000000 --- a/ServiceHost/DebugAdapter/AttachRequest.cs +++ /dev/null @@ -1,23 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class AttachRequest - { - public static readonly - RequestType Type = - RequestType.Create("attach"); - } - - public class AttachRequestArguments - { - public string Address { get; set; } - - public int Port { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/Breakpoint.cs b/ServiceHost/DebugAdapter/Breakpoint.cs deleted file mode 100644 index 14de1790..00000000 --- a/ServiceHost/DebugAdapter/Breakpoint.cs +++ /dev/null @@ -1,81 +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.Utility; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class Breakpoint - { - /// - /// Gets an boolean indicator that if true, breakpoint could be set - /// (but not necessarily at the desired location). - /// - public bool Verified { get; set; } - - /// - /// Gets an optional message about the state of the breakpoint. This is shown to the user - /// and can be used to explain why a breakpoint could not be verified. - /// - public string Message { get; set; } - - public string Source { get; set; } - - public int? Line { get; set; } - - public int? Column { get; set; } - - private Breakpoint() - { - } - -#if false - public static Breakpoint Create( - BreakpointDetails breakpointDetails) - { - //Validate.IsNotNull(nameof(breakpointDetails), breakpointDetails); - - return new Breakpoint - { - Verified = breakpointDetails.Verified, - Message = breakpointDetails.Message, - Source = breakpointDetails.Source, - Line = breakpointDetails.LineNumber, - Column = breakpointDetails.ColumnNumber - }; - } - - public static Breakpoint Create( - CommandBreakpointDetails breakpointDetails) - { - //Validate.IsNotNull(nameof(breakpointDetails), breakpointDetails); - - return new Breakpoint { - Verified = breakpointDetails.Verified, - Message = breakpointDetails.Message - }; - } -#endif - - public static Breakpoint Create( - SourceBreakpoint sourceBreakpoint, - string source, - string message, - bool verified = false) - { - Validate.IsNotNull(nameof(sourceBreakpoint), sourceBreakpoint); - Validate.IsNotNull(nameof(source), source); - Validate.IsNotNull(nameof(message), message); - - return new Breakpoint { - Verified = verified, - Message = message, - Source = source, - Line = sourceBreakpoint.Line, - Column = sourceBreakpoint.Column - }; - } - } -} diff --git a/ServiceHost/DebugAdapter/ConfigurationDoneRequest.cs b/ServiceHost/DebugAdapter/ConfigurationDoneRequest.cs deleted file mode 100644 index 2fc2203f..00000000 --- a/ServiceHost/DebugAdapter/ConfigurationDoneRequest.cs +++ /dev/null @@ -1,16 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class ConfigurationDoneRequest - { - public static readonly - RequestType Type = - RequestType.Create("configurationDone"); - } -} diff --git a/ServiceHost/DebugAdapter/ContinueRequest.cs b/ServiceHost/DebugAdapter/ContinueRequest.cs deleted file mode 100644 index c78dd0c3..00000000 --- a/ServiceHost/DebugAdapter/ContinueRequest.cs +++ /dev/null @@ -1,17 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class ContinueRequest - { - public static readonly - RequestType Type = - RequestType.Create("continue"); - } -} - diff --git a/ServiceHost/DebugAdapter/DisconnectRequest.cs b/ServiceHost/DebugAdapter/DisconnectRequest.cs deleted file mode 100644 index 43a25908..00000000 --- a/ServiceHost/DebugAdapter/DisconnectRequest.cs +++ /dev/null @@ -1,17 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class DisconnectRequest - { - public static readonly - RequestType Type = - RequestType.Create("disconnect"); - } -} - diff --git a/ServiceHost/DebugAdapter/EvaluateRequest.cs b/ServiceHost/DebugAdapter/EvaluateRequest.cs deleted file mode 100644 index 627a3c65..00000000 --- a/ServiceHost/DebugAdapter/EvaluateRequest.cs +++ /dev/null @@ -1,53 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class EvaluateRequest - { - public static readonly - RequestType Type = - RequestType.Create("evaluate"); - } - - public class EvaluateRequestArguments - { - /// - /// The expression to evaluate. - /// - public string Expression { get; set; } - - /// - /// The context in which the evaluate request is run. Possible - /// values are 'watch' if evaluate is run in a watch or 'repl' - /// if run from the REPL console. - /// - public string Context { get; set; } - - /// - /// Evaluate the expression in the context of this stack frame. - /// If not specified, the top most frame is used. - /// - public int FrameId { get; set; } - } - - public class EvaluateResponseBody - { - /// - /// The evaluation result. - /// - public string Result { get; set; } - - /// - /// If variablesReference is > 0, the evaluate result is - /// structured and its children can be retrieved by passing - /// variablesReference to the VariablesRequest - /// - public int VariablesReference { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/ExitedEvent.cs b/ServiceHost/DebugAdapter/ExitedEvent.cs deleted file mode 100644 index 5f35dbf5..00000000 --- a/ServiceHost/DebugAdapter/ExitedEvent.cs +++ /dev/null @@ -1,22 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class ExitedEvent - { - public static readonly - EventType Type = - EventType.Create("exited"); - } - - public class ExitedEventBody - { - public int ExitCode { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/InitializeRequest.cs b/ServiceHost/DebugAdapter/InitializeRequest.cs deleted file mode 100644 index d85de828..00000000 --- a/ServiceHost/DebugAdapter/InitializeRequest.cs +++ /dev/null @@ -1,56 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class InitializeRequest - { - public static readonly - RequestType Type = - RequestType.Create("initialize"); - } - - public class InitializeRequestArguments - { - public string AdapterId { get; set; } - - public bool LinesStartAt1 { get; set; } - - public string PathFormat { get; set; } - - public bool SourceMaps { get; set; } - - public string GeneratedCodeDirectory { get; set; } - } - - public class InitializeResponseBody - { - /// - /// Gets or sets a boolean value that determines whether the debug adapter - /// supports the configurationDoneRequest. - /// - public bool SupportsConfigurationDoneRequest { get; set; } - - /// - /// Gets or sets a boolean value that determines whether the debug adapter - /// supports functionBreakpoints. - /// - public bool SupportsFunctionBreakpoints { get; set; } - - /// - /// Gets or sets a boolean value that determines whether the debug adapter - /// supports conditionalBreakpoints. - /// - public bool SupportsConditionalBreakpoints { get; set; } - - /// - /// Gets or sets a boolean value that determines whether the debug adapter - /// supports a (side effect free) evaluate request for data hovers. - /// - public bool SupportsEvaluateForHovers { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/InitializedEvent.cs b/ServiceHost/DebugAdapter/InitializedEvent.cs deleted file mode 100644 index 2025ab07..00000000 --- a/ServiceHost/DebugAdapter/InitializedEvent.cs +++ /dev/null @@ -1,16 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class InitializedEvent - { - public static readonly - EventType Type = - EventType.Create("initialized"); - } -} diff --git a/ServiceHost/DebugAdapter/LaunchRequest.cs b/ServiceHost/DebugAdapter/LaunchRequest.cs deleted file mode 100644 index 0f1f3c55..00000000 --- a/ServiceHost/DebugAdapter/LaunchRequest.cs +++ /dev/null @@ -1,66 +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 System.Collections.Generic; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class LaunchRequest - { - public static readonly - RequestType Type = - RequestType.Create("launch"); - } - - public class LaunchRequestArguments - { - /// - /// Gets or sets the absolute path to the program to debug. - /// - public string Program { get; set; } - - /// - /// Gets or sets a boolean value that indicates whether the script should be - /// run with (false) or without (true) debugging support. - /// - public bool NoDebug { get; set; } - - /// - /// Gets or sets a boolean value that determines whether to automatically stop - /// target after launch. If not specified, target does not stop. - /// - public bool StopOnEntry { get; set; } - - /// - /// Gets or sets optional arguments passed to the debuggee. - /// - public string[] Args { get; set; } - - /// - /// Gets or sets the working directory of the launched debuggee (specified as an absolute path). - /// If omitted the debuggee is lauched in its own directory. - /// - public string Cwd { get; set; } - - /// - /// Gets or sets the absolute path to the runtime executable to be used. - /// Default is the runtime executable on the PATH. - /// - public string RuntimeExecutable { get; set; } - - /// - /// Gets or sets the optional arguments passed to the runtime executable. - /// - public string[] RuntimeArgs { get; set; } - - /// - /// Gets or sets optional environment variables to pass to the debuggee. The string valued - /// properties of the 'environmentVariables' are used as key/value pairs. - /// - public Dictionary Env { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/NextRequest.cs b/ServiceHost/DebugAdapter/NextRequest.cs deleted file mode 100644 index 8d41b539..00000000 --- a/ServiceHost/DebugAdapter/NextRequest.cs +++ /dev/null @@ -1,20 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - // /** StepOver request; value of command field is "next". - // he request starts the debuggee to run again for one step. - // penDebug will respond with a StoppedEvent (event type 'step') after running the step. - public class NextRequest - { - public static readonly - RequestType Type = - RequestType.Create("next"); - } -} - diff --git a/ServiceHost/DebugAdapter/OutputEvent.cs b/ServiceHost/DebugAdapter/OutputEvent.cs deleted file mode 100644 index ffc92491..00000000 --- a/ServiceHost/DebugAdapter/OutputEvent.cs +++ /dev/null @@ -1,24 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class OutputEvent - { - public static readonly - EventType Type = - EventType.Create("output"); - } - - public class OutputEventBody - { - public string Category { get; set; } - - public string Output { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/PauseRequest.cs b/ServiceHost/DebugAdapter/PauseRequest.cs deleted file mode 100644 index d99ec234..00000000 --- a/ServiceHost/DebugAdapter/PauseRequest.cs +++ /dev/null @@ -1,17 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class PauseRequest - { - public static readonly - RequestType Type = - RequestType.Create("pause"); - } -} - diff --git a/ServiceHost/DebugAdapter/Scope.cs b/ServiceHost/DebugAdapter/Scope.cs deleted file mode 100644 index a5235ece..00000000 --- a/ServiceHost/DebugAdapter/Scope.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class Scope - { - /// - /// Gets or sets the name of the scope (as such 'Arguments', 'Locals') - /// - public string Name { get; set; } - - /// - /// Gets or sets the variables of this scope can be retrieved by passing the - /// value of variablesReference to the VariablesRequest. - /// - public int VariablesReference { get; set; } - - /// - /// Gets or sets a boolean value indicating if number of variables in - /// this scope is large or expensive to retrieve. - /// - public bool Expensive { get; set; } - -#if false - public static Scope Create(VariableScope scope) - { - return new Scope { - Name = scope.Name, - VariablesReference = scope.Id, - // Temporary fix for #95 to get debug hover tips to work well at least for the local scope. - Expensive = (scope.Name != VariableContainerDetails.LocalScopeName) - }; - } -#endif - } -} - diff --git a/ServiceHost/DebugAdapter/ScopesRequest.cs b/ServiceHost/DebugAdapter/ScopesRequest.cs deleted file mode 100644 index 691f2eb5..00000000 --- a/ServiceHost/DebugAdapter/ScopesRequest.cs +++ /dev/null @@ -1,29 +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 System.Diagnostics; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class ScopesRequest - { - public static readonly - RequestType Type = - RequestType.Create("scopes"); - } - - [DebuggerDisplay("FrameId = {FrameId}")] - public class ScopesRequestArguments - { - public int FrameId { get; set; } - } - - public class ScopesResponseBody - { - public Scope[] Scopes { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/SetBreakpointsRequest.cs b/ServiceHost/DebugAdapter/SetBreakpointsRequest.cs deleted file mode 100644 index f8f3d416..00000000 --- a/ServiceHost/DebugAdapter/SetBreakpointsRequest.cs +++ /dev/null @@ -1,43 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - /// - /// SetBreakpoints request; value of command field is "setBreakpoints". - /// Sets multiple breakpoints for a single source and clears all previous breakpoints in that source. - /// To clear all breakpoint for a source, specify an empty array. - /// When a breakpoint is hit, a StoppedEvent (event type 'breakpoint') is generated. - /// - public class SetBreakpointsRequest - { - public static readonly - RequestType Type = - RequestType.Create("setBreakpoints"); - } - - public class SetBreakpointsRequestArguments - { - public Source Source { get; set; } - - public SourceBreakpoint[] Breakpoints { get; set; } - } - - public class SourceBreakpoint - { - public int Line { get; set; } - - public int? Column { get; set; } - - public string Condition { get; set; } - } - - public class SetBreakpointsResponseBody - { - public Breakpoint[] Breakpoints { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/SetExceptionBreakpointsRequest.cs b/ServiceHost/DebugAdapter/SetExceptionBreakpointsRequest.cs deleted file mode 100644 index 1ced918a..00000000 --- a/ServiceHost/DebugAdapter/SetExceptionBreakpointsRequest.cs +++ /dev/null @@ -1,31 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - /// - /// SetExceptionBreakpoints request; value of command field is "setExceptionBreakpoints". - /// Enable that the debuggee stops on exceptions with a StoppedEvent (event type 'exception'). - /// - public class SetExceptionBreakpointsRequest - { - public static readonly - RequestType Type = - RequestType.Create("setExceptionBreakpoints"); - } - - /// - /// Arguments for "setExceptionBreakpoints" request. - /// - public class SetExceptionBreakpointsRequestArguments - { - /// - /// Gets or sets the names of enabled exception breakpoints. - /// - public string[] Filters { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/SetFunctionBreakpointsRequest.cs b/ServiceHost/DebugAdapter/SetFunctionBreakpointsRequest.cs deleted file mode 100644 index e274fcd1..00000000 --- a/ServiceHost/DebugAdapter/SetFunctionBreakpointsRequest.cs +++ /dev/null @@ -1,31 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class SetFunctionBreakpointsRequest - { - public static readonly - RequestType Type = - RequestType.Create("setFunctionBreakpoints"); - } - - public class SetFunctionBreakpointsRequestArguments - { - public FunctionBreakpoint[] Breakpoints { get; set; } - } - - public class FunctionBreakpoint - { - /// - /// Gets or sets the name of the function to break on when it is invoked. - /// - public string Name { get; set; } - - public string Condition { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/Source.cs b/ServiceHost/DebugAdapter/Source.cs deleted file mode 100644 index e36b659d..00000000 --- a/ServiceHost/DebugAdapter/Source.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class Source - { - public string Name { get; set; } - - public string Path { get; set; } - - public int? SourceReference { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/SourceRequest.cs b/ServiceHost/DebugAdapter/SourceRequest.cs deleted file mode 100644 index f627aefc..00000000 --- a/ServiceHost/DebugAdapter/SourceRequest.cs +++ /dev/null @@ -1,29 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class SourceRequest - { - public static readonly - RequestType Type = - RequestType.Create("source"); - } - - public class SourceRequestArguments - { - /// - /// Gets or sets the reference to the source. This is the value received in Source.reference. - /// - public int SourceReference { get; set; } - } - - public class SourceResponseBody - { - public string Content { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/StackFrame.cs b/ServiceHost/DebugAdapter/StackFrame.cs deleted file mode 100644 index 90e6c243..00000000 --- a/ServiceHost/DebugAdapter/StackFrame.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StackFrame - { - public int Id { get; set; } - - public string Name { get; set; } - - public Source Source { get; set; } - - public int Line { get; set; } - - public int Column { get; set; } - - // /** An identifier for the stack frame. */ - //id: number; - ///** The name of the stack frame, typically a method name */ - //name: string; - ///** The source of the frame. */ - //source: Source; - ///** The line within the file of the frame. */ - //line: number; - ///** The column within the line. */ - //column: number; - ///** All arguments and variables declared in this stackframe. */ - //scopes: Scope[]; - -#if false - public static StackFrame Create( - StackFrameDetails stackFrame, - int id) - { - return new StackFrame - { - Id = id, - Name = stackFrame.FunctionName, - Line = stackFrame.LineNumber, - Column = stackFrame.ColumnNumber, - Source = new Source - { - Path = stackFrame.ScriptPath - } - }; - } -#endif - } -} - diff --git a/ServiceHost/DebugAdapter/StackTraceRequest.cs b/ServiceHost/DebugAdapter/StackTraceRequest.cs deleted file mode 100644 index cd0301c7..00000000 --- a/ServiceHost/DebugAdapter/StackTraceRequest.cs +++ /dev/null @@ -1,33 +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 System.Diagnostics; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StackTraceRequest - { - public static readonly - RequestType Type = - RequestType.Create("stackTrace"); - } - - [DebuggerDisplay("ThreadId = {ThreadId}, Levels = {Levels}")] - public class StackTraceRequestArguments - { - public int ThreadId { get; private set; } - - /// - /// Gets the maximum number of frames to return. If levels is not specified or 0, all frames are returned. - /// - public int Levels { get; private set; } - } - - public class StackTraceResponseBody - { - public StackFrame[] StackFrames { get; set; } - } -} diff --git a/ServiceHost/DebugAdapter/StartedEvent.cs b/ServiceHost/DebugAdapter/StartedEvent.cs deleted file mode 100644 index 9ecfd6a0..00000000 --- a/ServiceHost/DebugAdapter/StartedEvent.cs +++ /dev/null @@ -1,16 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StartedEvent - { - public static readonly - EventType Type = - EventType.Create("started"); - } -} diff --git a/ServiceHost/DebugAdapter/StepInRequest.cs b/ServiceHost/DebugAdapter/StepInRequest.cs deleted file mode 100644 index 42d935fb..00000000 --- a/ServiceHost/DebugAdapter/StepInRequest.cs +++ /dev/null @@ -1,17 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StepInRequest - { - public static readonly - RequestType Type = - RequestType.Create("stepIn"); - } -} - diff --git a/ServiceHost/DebugAdapter/StepOutRequest.cs b/ServiceHost/DebugAdapter/StepOutRequest.cs deleted file mode 100644 index 17e090a2..00000000 --- a/ServiceHost/DebugAdapter/StepOutRequest.cs +++ /dev/null @@ -1,16 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StepOutRequest - { - public static readonly - RequestType Type = - RequestType.Create("stepOut"); - } -} diff --git a/ServiceHost/DebugAdapter/StoppedEvent.cs b/ServiceHost/DebugAdapter/StoppedEvent.cs deleted file mode 100644 index 698bd698..00000000 --- a/ServiceHost/DebugAdapter/StoppedEvent.cs +++ /dev/null @@ -1,41 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class StoppedEvent - { - public static readonly - EventType Type = - EventType.Create("stopped"); - } - - public class StoppedEventBody - { - /// - /// A value such as "step", "breakpoint", "exception", or "pause" - /// - public string Reason { get; set; } - - /// - /// Gets or sets the current thread ID, if any. - /// - public int? ThreadId { get; set; } - - public Source Source { get; set; } - - public int Line { get; set; } - - public int Column { get; set; } - - /// - /// Gets or sets additional information such as an error message. - /// - public string Text { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/TerminatedEvent.cs b/ServiceHost/DebugAdapter/TerminatedEvent.cs deleted file mode 100644 index 5671a88e..00000000 --- a/ServiceHost/DebugAdapter/TerminatedEvent.cs +++ /dev/null @@ -1,17 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class TerminatedEvent - { - public static readonly - EventType Type = - EventType.Create("terminated"); - } -} - diff --git a/ServiceHost/DebugAdapter/Thread.cs b/ServiceHost/DebugAdapter/Thread.cs deleted file mode 100644 index 6bc26693..00000000 --- a/ServiceHost/DebugAdapter/Thread.cs +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class Thread - { - public int Id { get; set; } - - public string Name { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/ThreadsRequest.cs b/ServiceHost/DebugAdapter/ThreadsRequest.cs deleted file mode 100644 index c720cb5b..00000000 --- a/ServiceHost/DebugAdapter/ThreadsRequest.cs +++ /dev/null @@ -1,22 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class ThreadsRequest - { - public static readonly - RequestType Type = - RequestType.Create("threads"); - } - - public class ThreadsResponseBody - { - public Thread[] Threads { get; set; } - } -} - diff --git a/ServiceHost/DebugAdapter/Variable.cs b/ServiceHost/DebugAdapter/Variable.cs deleted file mode 100644 index e805dde9..00000000 --- a/ServiceHost/DebugAdapter/Variable.cs +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class Variable - { - public string Name { get; set; } - - // /** The variable's value. For structured objects this can be a multi line text, e.g. for a function the body of a function. */ - public string Value { get; set; } - - // /** If variablesReference is > 0, the variable is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. */ - public int VariablesReference { get; set; } - -#if false - public static Variable Create(VariableDetailsBase variable) - { - return new Variable - { - Name = variable.Name, - Value = variable.ValueString ?? string.Empty, - VariablesReference = - variable.IsExpandable ? - variable.Id : 0 - }; - } -#endif - } -} - diff --git a/ServiceHost/DebugAdapter/VariablesRequest.cs b/ServiceHost/DebugAdapter/VariablesRequest.cs deleted file mode 100644 index cd260b1b..00000000 --- a/ServiceHost/DebugAdapter/VariablesRequest.cs +++ /dev/null @@ -1,29 +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 System.Diagnostics; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter -{ - public class VariablesRequest - { - public static readonly - RequestType Type = - RequestType.Create("variables"); - } - - [DebuggerDisplay("VariablesReference = {VariablesReference}")] - public class VariablesRequestArguments - { - public int VariablesReference { get; set; } - } - - public class VariablesResponseBody - { - public Variable[] Variables { get; set; } - } -} - diff --git a/ServiceHost/LanguageServer/ClientCapabilities.cs b/ServiceHost/LanguageServer/ClientCapabilities.cs index 6537e7b5..70e2d068 100644 --- a/ServiceHost/LanguageServer/ClientCapabilities.cs +++ b/ServiceHost/LanguageServer/ClientCapabilities.cs @@ -3,11 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer { diff --git a/ServiceHost/LanguageServer/Completion.cs b/ServiceHost/LanguageServer/Completion.cs index 3af67735..5f26ea96 100644 --- a/ServiceHost/LanguageServer/Completion.cs +++ b/ServiceHost/LanguageServer/Completion.cs @@ -83,4 +83,3 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer public object Data { get; set; } } } - diff --git a/ServiceHost/LanguageServer/Diagnostics.cs b/ServiceHost/LanguageServer/Diagnostics.cs index 87c2f98f..a5472607 100644 --- a/ServiceHost/LanguageServer/Diagnostics.cs +++ b/ServiceHost/LanguageServer/Diagnostics.cs @@ -4,11 +4,6 @@ // using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer { diff --git a/ServiceHost/LanguageServer/EditorCommands.cs b/ServiceHost/LanguageServer/EditorCommands.cs deleted file mode 100644 index 426d7885..00000000 --- a/ServiceHost/LanguageServer/EditorCommands.cs +++ /dev/null @@ -1,111 +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.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer -{ - public class ExtensionCommandAddedNotification - { - public static readonly - EventType Type = - EventType.Create("SqlTools/extensionCommandAdded"); - - public string Name { get; set; } - - public string DisplayName { get; set; } - } - - public class ExtensionCommandUpdatedNotification - { - public static readonly - EventType Type = - EventType.Create("SqlTools/extensionCommandUpdated"); - - public string Name { get; set; } - } - - public class ExtensionCommandRemovedNotification - { - public static readonly - EventType Type = - EventType.Create("SqlTools/extensionCommandRemoved"); - - public string Name { get; set; } - } - - public class ClientEditorContext - { - public string CurrentFilePath { get; set; } - - public Position CursorPosition { get; set; } - - public Range SelectionRange { get; set; } - - } - - public class InvokeExtensionCommandRequest - { - public static readonly - RequestType Type = - RequestType.Create("SqlTools/invokeExtensionCommand"); - - public string Name { get; set; } - - public ClientEditorContext Context { get; set; } - } - - public class GetEditorContextRequest - { - public static readonly - RequestType Type = - RequestType.Create("editor/getEditorContext"); - } - - public enum EditorCommandResponse - { - Unsupported, - OK - } - - public class InsertTextRequest - { - public static readonly - RequestType Type = - RequestType.Create("editor/insertText"); - - public string FilePath { get; set; } - - public string InsertText { get; set; } - - public Range InsertRange { get; set; } - } - - public class SetSelectionRequest - { - public static readonly - RequestType Type = - RequestType.Create("editor/setSelection"); - - public Range SelectionRange { get; set; } - } - - public class SetCursorPositionRequest - { - public static readonly - RequestType Type = - RequestType.Create("editor/setCursorPosition"); - - public Position CursorPosition { get; set; } - } - - public class OpenFileRequest - { - public static readonly - RequestType Type = - RequestType.Create("editor/openFile"); - } -} - diff --git a/ServiceHost/LanguageServer/Hover.cs b/ServiceHost/LanguageServer/Hover.cs index 7a8b6cbf..2e196fba 100644 --- a/ServiceHost/LanguageServer/Hover.cs +++ b/ServiceHost/LanguageServer/Hover.cs @@ -4,11 +4,6 @@ // using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer { diff --git a/ServiceHost/MessageProtocol/Channel/NamedPipeClientChannel.cs b/ServiceHost/MessageProtocol/Channel/NamedPipeClientChannel.cs deleted file mode 100644 index 5af3711d..00000000 --- a/ServiceHost/MessageProtocol/Channel/NamedPipeClientChannel.cs +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#if false - -using System; -using System.IO.Pipes; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel -{ - public class NamedPipeClientChannel : ChannelBase - { - private string pipeName; - private bool isClientConnected; - private NamedPipeClientStream pipeClient; - - public NamedPipeClientChannel(string pipeName) - { - this.pipeName = pipeName; - } - - public override async Task WaitForConnection() - { -#if NanoServer - await this.pipeClient.ConnectAsync(); -#else - this.IsConnected = false; - - while (!this.IsConnected) - { - try - { - // Wait for 500 milliseconds so that we don't tie up the thread - this.pipeClient.Connect(500); - this.IsConnected = this.pipeClient.IsConnected; - } - catch (TimeoutException) - { - // Connect timed out, wait and try again - await Task.Delay(1000); - continue; - } - } -#endif - - // If we've reached this point, we're connected - this.IsConnected = true; - } - - protected override void Initialize(IMessageSerializer messageSerializer) - { - this.pipeClient = - new NamedPipeClientStream( - ".", - this.pipeName, - PipeDirection.InOut, - PipeOptions.Asynchronous); - - this.MessageReader = - new MessageReader( - this.pipeClient, - messageSerializer); - - this.MessageWriter = - new MessageWriter( - this.pipeClient, - messageSerializer); - } - - protected override void Shutdown() - { - if (this.pipeClient != null) - { - this.pipeClient.Dispose(); - } - } - } -} - -#endif \ No newline at end of file diff --git a/ServiceHost/MessageProtocol/Channel/NamedPipeServerChannel.cs b/ServiceHost/MessageProtocol/Channel/NamedPipeServerChannel.cs deleted file mode 100644 index 1a3a954a..00000000 --- a/ServiceHost/MessageProtocol/Channel/NamedPipeServerChannel.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#if false -using System; -using System.IO.Pipes; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel -{ - public class NamedPipeServerChannel : ChannelBase - { - private string pipeName; - private NamedPipeServerStream pipeServer; - - public NamedPipeServerChannel(string pipeName) - { - this.pipeName = pipeName; - } - - public override async Task WaitForConnection() - { -#if NanoServer - await this.pipeServer.WaitForConnectionAsync(); -#else - await Task.Factory.FromAsync(this.pipeServer.BeginWaitForConnection, this.pipeServer.EndWaitForConnection, null); -#endif - - this.IsConnected = true; - } - - protected override void Initialize(IMessageSerializer messageSerializer) - { - this.pipeServer = - new NamedPipeServerStream( - pipeName, - PipeDirection.InOut, - 1, - PipeTransmissionMode.Byte, - PipeOptions.Asynchronous); - - this.MessageReader = - new MessageReader( - this.pipeServer, - messageSerializer); - - this.MessageWriter = - new MessageWriter( - this.pipeServer, - messageSerializer); - } - - protected override void Shutdown() - { - if (this.pipeServer != null) - { - this.pipeServer.Dispose(); - } - } - } -} - -#endif diff --git a/ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs b/ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs index 3cf87be4..5390f52d 100644 --- a/ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs +++ b/ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs @@ -3,11 +3,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers; using System.Diagnostics; using System.IO; using System.Text; -using System; using System.Threading.Tasks; namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel diff --git a/ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs b/ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs index deb692e1..0b9376d4 100644 --- a/ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs +++ b/ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs @@ -3,10 +3,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers; using System.IO; using System.Text; -using System; using System.Threading.Tasks; namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel diff --git a/ServiceHost/Messages/PromptEvents.cs b/ServiceHost/Messages/PromptEvents.cs deleted file mode 100644 index 3be10f75..00000000 --- a/ServiceHost/Messages/PromptEvents.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#if false -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Messages -{ - public class ShowChoicePromptRequest - { - public static readonly - RequestType Type = - RequestType.Create("SqlTools/showChoicePrompt"); - - public string Caption { get; set; } - - public string Message { get; set; } - - public ChoiceDetails[] Choices { get; set; } - - public int DefaultChoice { get; set; } - } - - public class ShowChoicePromptResponse - { - public bool PromptCancelled { get; set; } - - public string ChosenItem { get; set; } - } - - public class ShowInputPromptRequest - { - public static readonly - RequestType Type = - RequestType.Create("SqlTools/showInputPrompt"); - - /// - /// Gets or sets the name of the field. - /// - public string Name { get; set; } - - /// - /// Gets or sets the descriptive label for the field. - /// - public string Label { get; set; } - } - - public class ShowInputPromptResponse - { - public bool PromptCancelled { get; set; } - - public string ResponseText { get; set; } - } -} - -#endif \ No newline at end of file diff --git a/ServiceHost/Properties/AssemblyInfo.cs b/ServiceHost/Properties/AssemblyInfo.cs index 8f6b28ad..27c1daba 100644 --- a/ServiceHost/Properties/AssemblyInfo.cs +++ b/ServiceHost/Properties/AssemblyInfo.cs @@ -15,7 +15,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("SqlTools Editor Services")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyCopyright("� Microsoft Corporation. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -37,8 +37,8 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.0.0.0")] -[assembly: AssemblyFileVersion("0.0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0.0")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyInformationalVersion("1.0.0.0")] [assembly: InternalsVisibleTo("Microsoft.SqlTools.EditorServices.Test.Protocol")] diff --git a/ServiceHost/Server/DebugAdapter.cs b/ServiceHost/Server/DebugAdapter.cs deleted file mode 100644 index d62b10e9..00000000 --- a/ServiceHost/Server/DebugAdapter.cs +++ /dev/null @@ -1,584 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#if false - -using Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel; -using Microsoft.SqlTools.EditorServices.Session; -using Microsoft.SqlTools.EditorServices.Utility; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Server -{ - public class DebugAdapter : DebugAdapterBase - { - private EditorSession editorSession; - private OutputDebouncer outputDebouncer; - private bool isConfigurationDoneRequestComplete; - private bool isLaunchRequestComplete; - private bool noDebug; - private string scriptPathToLaunch; - private string arguments; - - public DebugAdapter(HostDetails hostDetails, ProfilePaths profilePaths) - : this(hostDetails, profilePaths, new StdioServerChannel()) - { - } - - public DebugAdapter(HostDetails hostDetails, ProfilePaths profilePaths, ChannelBase serverChannel) - : base(serverChannel) - { - this.editorSession = new EditorSession(); - this.editorSession.StartSession(hostDetails, profilePaths); - this.editorSession.DebugService.DebuggerStopped += this.DebugService_DebuggerStopped; - this.editorSession.ConsoleService.OutputWritten += this.SqlToolsContext_OutputWritten; - - // Set up the output debouncer to throttle output event writes - this.outputDebouncer = new OutputDebouncer(this); - } - - protected override void Initialize() - { - // Register all supported message types - - this.SetRequestHandler(LaunchRequest.Type, this.HandleLaunchRequest); - this.SetRequestHandler(AttachRequest.Type, this.HandleAttachRequest); - this.SetRequestHandler(ConfigurationDoneRequest.Type, this.HandleConfigurationDoneRequest); - this.SetRequestHandler(DisconnectRequest.Type, this.HandleDisconnectRequest); - - this.SetRequestHandler(SetBreakpointsRequest.Type, this.HandleSetBreakpointsRequest); - this.SetRequestHandler(SetExceptionBreakpointsRequest.Type, this.HandleSetExceptionBreakpointsRequest); - this.SetRequestHandler(SetFunctionBreakpointsRequest.Type, this.HandleSetFunctionBreakpointsRequest); - - this.SetRequestHandler(ContinueRequest.Type, this.HandleContinueRequest); - this.SetRequestHandler(NextRequest.Type, this.HandleNextRequest); - this.SetRequestHandler(StepInRequest.Type, this.HandleStepInRequest); - this.SetRequestHandler(StepOutRequest.Type, this.HandleStepOutRequest); - this.SetRequestHandler(PauseRequest.Type, this.HandlePauseRequest); - - this.SetRequestHandler(ThreadsRequest.Type, this.HandleThreadsRequest); - this.SetRequestHandler(StackTraceRequest.Type, this.HandleStackTraceRequest); - this.SetRequestHandler(ScopesRequest.Type, this.HandleScopesRequest); - this.SetRequestHandler(VariablesRequest.Type, this.HandleVariablesRequest); - this.SetRequestHandler(SourceRequest.Type, this.HandleSourceRequest); - this.SetRequestHandler(EvaluateRequest.Type, this.HandleEvaluateRequest); - } - - protected Task LaunchScript(RequestContext requestContext) - { - return editorSession.SqlToolsContext - .ExecuteScriptAtPath(this.scriptPathToLaunch, this.arguments) - .ContinueWith( - async (t) => { - Logger.Write(LogLevel.Verbose, "Execution completed, terminating..."); - - await requestContext.SendEvent( - TerminatedEvent.Type, - null); - - // Stop the server - await this.Stop(); - - // Notify that the session has ended - this.OnSessionEnded(); - }); - } - - protected override void Shutdown() - { - // Make sure remaining output is flushed before exiting - this.outputDebouncer.Flush().Wait(); - - Logger.Write(LogLevel.Normal, "Debug adapter is shutting down..."); - - if (this.editorSession != null) - { - this.editorSession.Dispose(); - this.editorSession = null; - } - } - - #region Built-in Message Handlers - - protected async Task HandleConfigurationDoneRequest( - object args, - RequestContext requestContext) - { - // The order of debug protocol messages apparently isn't as guaranteed as we might like. - // Need to be able to handle the case where we get the configurationDone request after the - // launch request. - if (this.isLaunchRequestComplete) - { - this.LaunchScript(requestContext); - } - - this.isConfigurationDoneRequestComplete = true; - - await requestContext.SendResult(null); - } - - protected async Task HandleLaunchRequest( - LaunchRequestArguments launchParams, - RequestContext requestContext) - { - // Set the working directory for the SqlTools runspace to the cwd passed in via launch.json. - // In case that is null, use the the folder of the script to be executed. If the resulting - // working dir path is a file path then extract the directory and use that. - string workingDir = launchParams.Cwd ?? launchParams.Program; - workingDir = SqlToolsContext.UnescapePath(workingDir); - try - { - if ((File.GetAttributes(workingDir) & FileAttributes.Directory) != FileAttributes.Directory) - { - workingDir = Path.GetDirectoryName(workingDir); - } - } - catch (Exception ex) - { - Logger.Write(LogLevel.Error, "cwd path is invalid: " + ex.Message); - -#if NanoServer - workingDir = AppContext.BaseDirectory; -#else - workingDir = Environment.CurrentDirectory; -#endif - } - - editorSession.SqlToolsContext.SetWorkingDirectory(workingDir); - Logger.Write(LogLevel.Verbose, "Working dir set to: " + workingDir); - - // Prepare arguments to the script - if specified - string arguments = null; - if ((launchParams.Args != null) && (launchParams.Args.Length > 0)) - { - arguments = string.Join(" ", launchParams.Args); - Logger.Write(LogLevel.Verbose, "Script arguments are: " + arguments); - } - - // We may not actually launch the script in response to this - // request unless it comes after the configurationDone request. - // If the launch request comes first, then stash the launch - // params so that the subsequent configurationDone request handler - // can launch the script. - this.noDebug = launchParams.NoDebug; - this.scriptPathToLaunch = launchParams.Program; - this.arguments = arguments; - - // The order of debug protocol messages apparently isn't as guaranteed as we might like. - // Need to be able to handle the case where we get the launch request after the - // configurationDone request. - if (this.isConfigurationDoneRequestComplete) - { - this.LaunchScript(requestContext); - } - - this.isLaunchRequestComplete = true; - - await requestContext.SendResult(null); - } - - protected Task HandleAttachRequest( - AttachRequestArguments attachParams, - RequestContext requestContext) - { - // TODO: Implement this once we support attaching to processes - throw new NotImplementedException(); - } - - protected Task HandleDisconnectRequest( - object disconnectParams, - RequestContext requestContext) - { - EventHandler handler = null; - - handler = - async (o, e) => - { - if (e.NewSessionState == SqlToolsContextState.Ready) - { - await requestContext.SendResult(null); - editorSession.SqlToolsContext.SessionStateChanged -= handler; - - // Stop the server - this.Stop(); - } - }; - - editorSession.SqlToolsContext.SessionStateChanged += handler; - editorSession.SqlToolsContext.AbortExecution(); - - return Task.FromResult(true); - } - - protected async Task HandleSetBreakpointsRequest( - SetBreakpointsRequestArguments setBreakpointsParams, - RequestContext requestContext) - { - ScriptFile scriptFile; - - // Fix for issue #195 - user can change name of file outside of VSCode in which case - // VSCode sends breakpoint requests with the original filename that doesn't exist anymore. - try - { - scriptFile = editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path); - } - catch (FileNotFoundException) - { - Logger.Write( - LogLevel.Warning, - $"Attempted to set breakpoints on a non-existing file: {setBreakpointsParams.Source.Path}"); - - string message = this.noDebug ? string.Empty : "Source does not exist, breakpoint not set."; - - var srcBreakpoints = setBreakpointsParams.Breakpoints - .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( - srcBkpt, setBreakpointsParams.Source.Path, message, verified: this.noDebug)); - - // Return non-verified breakpoint message. - await requestContext.SendResult( - new SetBreakpointsResponseBody { - Breakpoints = srcBreakpoints.ToArray() - }); - - return; - } - - var breakpointDetails = new BreakpointDetails[setBreakpointsParams.Breakpoints.Length]; - for (int i = 0; i < breakpointDetails.Length; i++) - { - SourceBreakpoint srcBreakpoint = setBreakpointsParams.Breakpoints[i]; - breakpointDetails[i] = BreakpointDetails.Create( - scriptFile.FilePath, - srcBreakpoint.Line, - srcBreakpoint.Column, - srcBreakpoint.Condition); - } - - // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. - BreakpointDetails[] updatedBreakpointDetails = breakpointDetails; - if (!this.noDebug) - { - updatedBreakpointDetails = - await editorSession.DebugService.SetLineBreakpoints( - scriptFile, - breakpointDetails); - } - - await requestContext.SendResult( - new SetBreakpointsResponseBody { - Breakpoints = - updatedBreakpointDetails - .Select(Protocol.DebugAdapter.Breakpoint.Create) - .ToArray() - }); - } - - protected async Task HandleSetFunctionBreakpointsRequest( - SetFunctionBreakpointsRequestArguments setBreakpointsParams, - RequestContext requestContext) - { - var breakpointDetails = new CommandBreakpointDetails[setBreakpointsParams.Breakpoints.Length]; - for (int i = 0; i < breakpointDetails.Length; i++) - { - FunctionBreakpoint funcBreakpoint = setBreakpointsParams.Breakpoints[i]; - breakpointDetails[i] = CommandBreakpointDetails.Create( - funcBreakpoint.Name, - funcBreakpoint.Condition); - } - - // If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints. - CommandBreakpointDetails[] updatedBreakpointDetails = breakpointDetails; - if (!this.noDebug) - { - updatedBreakpointDetails = - await editorSession.DebugService.SetCommandBreakpoints( - breakpointDetails); - } - - await requestContext.SendResult( - new SetBreakpointsResponseBody { - Breakpoints = - updatedBreakpointDetails - .Select(Protocol.DebugAdapter.Breakpoint.Create) - .ToArray() - }); - } - - protected async Task HandleSetExceptionBreakpointsRequest( - SetExceptionBreakpointsRequestArguments setExceptionBreakpointsParams, - RequestContext requestContext) - { - // TODO: Handle this appropriately - - await requestContext.SendResult(null); - } - - protected async Task HandleContinueRequest( - object continueParams, - RequestContext requestContext) - { - editorSession.DebugService.Continue(); - - await requestContext.SendResult(null); - } - - protected async Task HandleNextRequest( - object nextParams, - RequestContext requestContext) - { - editorSession.DebugService.StepOver(); - - await requestContext.SendResult(null); - } - - protected Task HandlePauseRequest( - object pauseParams, - RequestContext requestContext) - { - try - { - editorSession.DebugService.Break(); - } - catch (NotSupportedException e) - { - return requestContext.SendError(e.Message); - } - - // This request is responded to by sending the "stopped" event - return Task.FromResult(true); - } - - protected async Task HandleStepInRequest( - object stepInParams, - RequestContext requestContext) - { - editorSession.DebugService.StepIn(); - - await requestContext.SendResult(null); - } - - protected async Task HandleStepOutRequest( - object stepOutParams, - RequestContext requestContext) - { - editorSession.DebugService.StepOut(); - - await requestContext.SendResult(null); - } - - protected async Task HandleThreadsRequest( - object threadsParams, - RequestContext requestContext) - { - await requestContext.SendResult( - new ThreadsResponseBody - { - Threads = new Thread[] - { - // TODO: What do I do with these? - new Thread - { - Id = 1, - Name = "Main Thread" - } - } - }); - } - - protected async Task HandleStackTraceRequest( - StackTraceRequestArguments stackTraceParams, - RequestContext requestContext) - { - StackFrameDetails[] stackFrames = - editorSession.DebugService.GetStackFrames(); - - List newStackFrames = new List(); - - for (int i = 0; i < stackFrames.Length; i++) - { - // Create the new StackFrame object with an ID that can - // be referenced back to the current list of stack frames - newStackFrames.Add( - StackFrame.Create( - stackFrames[i], - i)); - } - - await requestContext.SendResult( - new StackTraceResponseBody - { - StackFrames = newStackFrames.ToArray() - }); - } - - protected async Task HandleScopesRequest( - ScopesRequestArguments scopesParams, - RequestContext requestContext) - { - VariableScope[] variableScopes = - editorSession.DebugService.GetVariableScopes( - scopesParams.FrameId); - - await requestContext.SendResult( - new ScopesResponseBody - { - Scopes = - variableScopes - .Select(Scope.Create) - .ToArray() - }); - } - - protected async Task HandleVariablesRequest( - VariablesRequestArguments variablesParams, - RequestContext requestContext) - { - VariableDetailsBase[] variables = - editorSession.DebugService.GetVariables( - variablesParams.VariablesReference); - - VariablesResponseBody variablesResponse = null; - - try - { - variablesResponse = new VariablesResponseBody - { - Variables = - variables - .Select(Variable.Create) - .ToArray() - }; - } - catch (Exception) - { - // TODO: This shouldn't be so broad - } - - await requestContext.SendResult(variablesResponse); - } - - protected Task HandleSourceRequest( - SourceRequestArguments sourceParams, - RequestContext requestContext) - { - // TODO: Implement this message. For now, doesn't seem to - // be a problem that it's missing. - - return Task.FromResult(true); - } - - protected async Task HandleEvaluateRequest( - EvaluateRequestArguments evaluateParams, - RequestContext requestContext) - { - string valueString = null; - int variableId = 0; - - bool isFromRepl = - string.Equals( - evaluateParams.Context, - "repl", - StringComparison.CurrentCultureIgnoreCase); - - if (isFromRepl) - { - // Send the input through the console service - editorSession.ConsoleService.ExecuteCommand( - evaluateParams.Expression, - false); - } - else - { - VariableDetails result = - await editorSession.DebugService.EvaluateExpression( - evaluateParams.Expression, - evaluateParams.FrameId, - isFromRepl); - - if (result != null) - { - valueString = result.ValueString; - variableId = - result.IsExpandable ? - result.Id : 0; - } - } - - await requestContext.SendResult( - new EvaluateResponseBody - { - Result = valueString, - VariablesReference = variableId - }); - } - - #endregion - - #region Events - - public event EventHandler SessionEnded; - - protected virtual void OnSessionEnded() - { - this.SessionEnded?.Invoke(this, null); - } - - #endregion - - #region Event Handlers - - async void DebugService_DebuggerStopped(object sender, DebuggerStopEventArgs e) - { - // Flush pending output before sending the event - await this.outputDebouncer.Flush(); - - // Provide the reason for why the debugger has stopped script execution. - // See https://github.com/Microsoft/vscode/issues/3648 - // The reason is displayed in the breakpoints viewlet. Some recommended reasons are: - // "step", "breakpoint", "function breakpoint", "exception" and "pause". - // We don't support exception breakpoints and for "pause", we can't distinguish - // between stepping and the user pressing the pause/break button in the debug toolbar. - string debuggerStoppedReason = "step"; - if (e.Breakpoints.Count > 0) - { - debuggerStoppedReason = - e.Breakpoints[0] is CommandBreakpoint - ? "function breakpoint" - : "breakpoint"; - } - - await this.SendEvent( - StoppedEvent.Type, - new StoppedEventBody - { - Source = new Source - { - Path = e.InvocationInfo.ScriptName, - }, - Line = e.InvocationInfo.ScriptLineNumber, - Column = e.InvocationInfo.OffsetInLine, - ThreadId = 1, // TODO: Change this based on context - Reason = debuggerStoppedReason - }); - } - - async void SqlToolsContext_OutputWritten(object sender, OutputWrittenEventArgs e) - { - // Queue the output for writing - await this.outputDebouncer.Invoke(e); - } - - #endregion - } -} - -#endif \ No newline at end of file diff --git a/ServiceHost/Server/DebugAdapterBase.cs b/ServiceHost/Server/DebugAdapterBase.cs deleted file mode 100644 index b0f85aab..00000000 --- a/ServiceHost/Server/DebugAdapterBase.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// -#if false -using Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Server -{ - public abstract class DebugAdapterBase : ProtocolEndpoint - { - public DebugAdapterBase(ChannelBase serverChannel) - : base (serverChannel, MessageProtocolType.DebugAdapter) - { - } - - /// - /// Overridden by the subclass to provide initialization - /// logic after the server channel is started. - /// - protected abstract void Initialize(); - - /// - /// Can be overridden by the subclass to provide shutdown - /// logic before the server exits. - /// - protected virtual void Shutdown() - { - // No default implementation yet. - } - - protected override Task OnStart() - { - // Register handlers for server lifetime messages - this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest); - - // Initialize the implementation class - this.Initialize(); - - return Task.FromResult(true); - } - - protected override Task OnStop() - { - this.Shutdown(); - - return Task.FromResult(true); - } - - private async Task HandleInitializeRequest( - object shutdownParams, - RequestContext requestContext) - { - // Now send the Initialize response to continue setup - await requestContext.SendResult( - new InitializeResponseBody { - SupportsConfigurationDoneRequest = true, - SupportsConditionalBreakpoints = true, - SupportsFunctionBreakpoints = true - }); - - // Send the Initialized event so that we get breakpoints - await requestContext.SendEvent( - InitializedEvent.Type, - null); - } - } -} - -#endif \ No newline at end of file diff --git a/ServiceHost/Server/LanguageServer.cs b/ServiceHost/Server/LanguageServer.cs index 69fddc5e..4f7367a4 100644 --- a/ServiceHost/Server/LanguageServer.cs +++ b/ServiceHost/Server/LanguageServer.cs @@ -2,171 +2,56 @@ // 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.Extensions; 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 Microsoft.SqlTools.EditorServices.Utility; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -//using System.Management.Automation; -//using System.Text.RegularExpressions; -using System.Threading; using System.Threading.Tasks; -using DebugAdapterMessages = Microsoft.SqlTools.EditorServices.Protocol.DebugAdapter; +using Microsoft.SqlTools.EditorServices.Utility; namespace Microsoft.SqlTools.EditorServices.Protocol.Server { public class LanguageServer : LanguageServerBase { - // private static CancellationTokenSource existingRequestCancellation; - - // private bool profilesLoaded; - // private EditorSession editorSession; - // private OutputDebouncer outputDebouncer; - // private LanguageServerEditorOperations editorOperations; - // private LanguageServerSettings currentSettings = new LanguageServerSettings(); - /// /// Provides details about the host application. /// public LanguageServer(HostDetails hostDetails, ProfilePaths profilePaths) - : this(hostDetails, profilePaths, new StdioServerChannel()) + : base(new StdioServerChannel()) { } - /// - /// Provides details about the host application. - /// - public LanguageServer(HostDetails hostDetails, ProfilePaths profilePaths, ChannelBase serverChannel) - : base(serverChannel) - { -#if false - this.editorSession = new EditorSession(); - this.editorSession.StartSession(hostDetails, profilePaths); - this.editorSession.ConsoleService.OutputWritten += this.SqlToolsContext_OutputWritten; - - // Attach to ExtensionService events - this.editorSession.ExtensionService.CommandAdded += ExtensionService_ExtensionAdded; - this.editorSession.ExtensionService.CommandUpdated += ExtensionService_ExtensionUpdated; - this.editorSession.ExtensionService.CommandRemoved += ExtensionService_ExtensionRemoved; - - // Create the IEditorOperations implementation - this.editorOperations = - new LanguageServerEditorOperations( - this.editorSession, - this); - - // Always send console prompts through the UI in the language service - // TODO: This will change later once we have a general REPL available - // in VS Code. - this.editorSession.ConsoleService.PushPromptHandlerContext( - new ProtocolPromptHandlerContext( - this, - this.editorSession.ConsoleService)); - - // Set up the output debouncer to throttle output event writes - this.outputDebouncer = new OutputDebouncer(this); -#endif - } - -protected async Task HandleInitializeRequest( - InitializeRequest initializeParams, - RequestContext requestContext) - { - // 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? - } - } - }); - } - 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.SetEventHandler(DidOpenTextDocumentNotification.Type, this.HandleDidOpenTextDocumentNotification); - // this.SetEventHandler(DidCloseTextDocumentNotification.Type, this.HandleDidCloseTextDocumentNotification); - // this.SetEventHandler(DidChangeTextDocumentNotification.Type, this.HandleDidChangeTextDocumentNotification); - // 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(ShowOnlineHelpRequest.Type, this.HandleShowOnlineHelpRequest); - // this.SetRequestHandler(ExpandAliasRequest.Type, this.HandleExpandAliasRequest); - - // this.SetRequestHandler(FindModuleRequest.Type, this.HandleFindModuleRequest); - // this.SetRequestHandler(InstallModuleRequest.Type, this.HandleInstallModuleRequest); - - // this.SetRequestHandler(InvokeExtensionCommandRequest.Type, this.HandleInvokeExtensionCommandRequest); - - // this.SetRequestHandler(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest); - -#if false - // Initialize the extension service - // TODO: This should be made awaited once Initialize is async! - this.editorSession.ExtensionService.Initialize( - this.editorOperations).Wait(); -#endif + 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); } -#if false protected override async Task Shutdown() { - // Make sure remaining output is flushed before exiting - await this.outputDebouncer.Flush(); - - //Logger.Write(LogLevel.Normal, "Language service is shutting down..."); - - if (this.editorSession != null) - { - this.editorSession.Dispose(); - this.editorSession = null; - } + await Task.FromResult(true); } - #region Built-in Message Handlers - protected async Task HandleInitializeRequest( InitializeRequest initializeParams, RequestContext requestContext) { + Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification"); + // Grab the workspace path from the parameters //editorSession.Workspace.WorkspacePath = initializeParams.RootPath; @@ -195,185 +80,27 @@ protected async Task HandleInitializeRequest( }); } - protected async Task HandleShowOnlineHelpRequest( - string helpParams, - RequestContext requestContext) - { - if (helpParams == null) { helpParams = "get-help"; } - - var psCommand = new PSCommand(); - psCommand.AddCommand("Get-Help"); - psCommand.AddArgument(helpParams); - psCommand.AddParameter("Online"); - - await editorSession.SqlToolsContext.ExecuteCommand(psCommand); - - await requestContext.SendResult(null); - } - - private async Task HandleInstallModuleRequest( - string moduleName, - RequestContext requestContext - ) - { - var script = string.Format("Install-Module -Name {0} -Scope CurrentUser", moduleName); - - var executeTask = - editorSession.SqlToolsContext.ExecuteScriptString( - script, - true, - true).ConfigureAwait(false); - - await requestContext.SendResult(null); - } - - private Task HandleInvokeExtensionCommandRequest( - InvokeExtensionCommandRequest commandDetails, - RequestContext requestContext) - { - // We don't await the result of the execution here because we want - // to be able to receive further messages while the editor command - // is executing. This important in cases where the pipeline thread - // gets blocked by something in the script like a prompt to the user. - EditorContext editorContext = - this.editorOperations.ConvertClientEditorContext( - commandDetails.Context); - - Task commandTask = - this.editorSession.ExtensionService.InvokeCommand( - commandDetails.Name, - editorContext); - - commandTask.ContinueWith(t => - { - return requestContext.SendResult(null); - }); - - return Task.FromResult(true); - } - - private async Task HandleExpandAliasRequest( - string content, - RequestContext requestContext) - { - var script = @" -function __Expand-Alias { - - param($targetScript) - - [ref]$errors=$null - - $tokens = [System.Management.Automation.PsParser]::Tokenize($targetScript, $errors).Where({$_.type -eq 'command'}) | - Sort Start -Descending - - foreach ($token in $tokens) { - $definition=(Get-Command ('`'+$token.Content) -CommandType Alias -ErrorAction SilentlyContinue).Definition - - if($definition) { - $lhs=$targetScript.Substring(0, $token.Start) - $rhs=$targetScript.Substring($token.Start + $token.Length) - - $targetScript=$lhs + $definition + $rhs - } - } - - $targetScript -}"; - var psCommand = new PSCommand(); - psCommand.AddScript(script); - await this.editorSession.SqlToolsContext.ExecuteCommand(psCommand); - - psCommand = new PSCommand(); - psCommand.AddCommand("__Expand-Alias").AddArgument(content); - var result = await this.editorSession.SqlToolsContext.ExecuteCommand(psCommand); - - await requestContext.SendResult(result.First().ToString()); - } - - private async Task HandleFindModuleRequest( - object param, - RequestContext requestContext) - { - var psCommand = new PSCommand(); - psCommand.AddScript("Find-Module | Select Name, Description"); - - var modules = await editorSession.SqlToolsContext.ExecuteCommand(psCommand); - - var moduleList = new List(); - - if (modules != null) - { - foreach (dynamic m in modules) - { - moduleList.Add(new PSModuleMessage { Name = m.Name, Description = m.Description }); - } - } - - await requestContext.SendResult(moduleList); - } - - protected Task HandleDidOpenTextDocumentNotification( - DidOpenTextDocumentNotification openParams, - EventContext eventContext) - { - ScriptFile openedFile = - editorSession.Workspace.GetFileBuffer( - openParams.Uri, - openParams.Text); - - // TODO: Get all recently edited files in the workspace - this.RunScriptDiagnostics( - new ScriptFile[] { openedFile }, - editorSession, - eventContext); - - Logger.Write(LogLevel.Verbose, "Finished opening document."); - - return Task.FromResult(true); - } - - protected Task HandleDidCloseTextDocumentNotification( - TextDocumentIdentifier closeParams, - EventContext eventContext) - { - // Find and close the file in the current session - var fileToClose = editorSession.Workspace.GetFile(closeParams.Uri); - - if (fileToClose != null) - { - editorSession.Workspace.CloseFile(fileToClose); - } - - Logger.Write(LogLevel.Verbose, "Finished closing document."); - - return Task.FromResult(true); - } - protected Task HandleDidChangeTextDocumentNotification( DidChangeTextDocumentParams textChangeParams, EventContext eventContext) { - List changedFiles = new List(); + Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification"); + return Task.FromResult(true); + } - // A text change notification can batch multiple change requests - foreach (var textChange in textChangeParams.ContentChanges) - { - ScriptFile changedFile = editorSession.Workspace.GetFile(textChangeParams.Uri); - - changedFile.ApplyChange( - GetFileChangeDetails( - textChange.Range.Value, - textChange.Text)); - - changedFiles.Add(changedFile); - } - - // TODO: Get all recently edited files in the workspace - this.RunScriptDiagnostics( - changedFiles.ToArray(), - editorSession, - eventContext); + protected Task HandleDidOpenTextDocumentNotification( + DidOpenTextDocumentNotification openParams, + EventContext eventContext) + { + Logger.Write(LogLevel.Normal, "HandleDidOpenTextDocumentNotification"); + return Task.FromResult(true); + } + protected Task HandleDidCloseTextDocumentNotification( + TextDocumentIdentifier closeParams, + EventContext eventContext) + { + Logger.Write(LogLevel.Normal, "HandleDidCloseTextDocumentNotification"); return Task.FromResult(true); } @@ -381,882 +108,80 @@ function __Expand-Alias { DidChangeConfigurationParams configChangeParams, EventContext eventContext) { - 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 (!this.profilesLoaded && - this.currentSettings.EnableProfileLoading && - oldLoadProfiles != this.currentSettings.EnableProfileLoading) - { - await this.editorSession.SqlToolsContext.LoadHostProfiles(); - this.profilesLoaded = true; - } - - // If there is a new settings file path, restart the analyzer with the new settigs. - bool settingsPathChanged = false; - string newSettingsPath = this.currentSettings.ScriptAnalysis.SettingsPath; - if (!string.Equals(oldScriptAnalysisSettingsPath, newSettingsPath, StringComparison.OrdinalIgnoreCase)) - { - this.editorSession.RestartAnalysisService(newSettingsPath); - settingsPathChanged = true; - } - - // If script analysis settings have changed we need to clear & possibly update the current diagnostic records. - if ((oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable) || settingsPathChanged) - { - // 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 || settingsPathChanged) - { - ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0]; - - foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles()) - { - await PublishScriptDiagnostics( - scriptFile, - emptyAnalysisDiagnostics, - eventContext); - } - } - - // If script analysis is enabled and the settings file changed get new diagnostic records. - if (this.currentSettings.ScriptAnalysis.Enable.Value && settingsPathChanged) - { - await this.RunScriptDiagnostics( - this.editorSession.Workspace.GetOpenedFiles(), - this.editorSession, - eventContext); - } - } + Logger.Write(LogLevel.Normal, "HandleDidChangeConfigurationNotification"); + await Task.FromResult(true); } protected async Task HandleDefinitionRequest( TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentPosition.Uri); - - SymbolReference foundSymbol = - editorSession.LanguageService.FindSymbolAtLocation( - scriptFile, - textDocumentPosition.Position.Line + 1, - textDocumentPosition.Position.Character + 1); - - List definitionLocations = new List(); - - GetDefinitionResult definition = null; - if (foundSymbol != null) - { - definition = - await editorSession.LanguageService.GetDefinitionOfSymbol( - scriptFile, - foundSymbol, - editorSession.Workspace); - - if (definition != null) - { - definitionLocations.Add( - new Location - { - Uri = new Uri(definition.FoundDefinition.FilePath).AbsoluteUri, - Range = GetRangeFromScriptRegion(definition.FoundDefinition.ScriptRegion) - }); - } - } - - await requestContext.SendResult(definitionLocations.ToArray()); + Logger.Write(LogLevel.Normal, "HandleDefinitionRequest"); + await Task.FromResult(true); } protected async Task HandleReferencesRequest( ReferencesParams referencesParams, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - referencesParams.Uri); - - SymbolReference foundSymbol = - editorSession.LanguageService.FindSymbolAtLocation( - scriptFile, - referencesParams.Position.Line + 1, - referencesParams.Position.Character + 1); - - FindReferencesResult referencesResult = - await editorSession.LanguageService.FindReferencesOfSymbol( - foundSymbol, - editorSession.Workspace.ExpandScriptReferences(scriptFile)); - - Location[] referenceLocations = null; - - if (referencesResult != null) - { - referenceLocations = - referencesResult - .FoundReferences - .Select(r => - { - return new Location - { - Uri = new Uri(r.FilePath).AbsoluteUri, - Range = GetRangeFromScriptRegion(r.ScriptRegion) - }; - }) - .ToArray(); - } - else - { - referenceLocations = new Location[0]; - } - - await requestContext.SendResult(referenceLocations); + Logger.Write(LogLevel.Normal, "HandleReferencesRequest"); + await Task.FromResult(true); } protected async Task HandleCompletionRequest( TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - int cursorLine = textDocumentPosition.Position.Line + 1; - int cursorColumn = textDocumentPosition.Position.Character + 1; - - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentPosition.Uri); - - CompletionResults completionResults = - await editorSession.LanguageService.GetCompletionsInFile( - scriptFile, - cursorLine, - cursorColumn); - - CompletionItem[] completionItems = null; - - if (completionResults != null) - { - int sortIndex = 1; - completionItems = - completionResults - .Completions - .Select( - c => CreateCompletionItem( - c, - completionResults.ReplacedRange, - sortIndex++)) - .ToArray(); - } - else - { - completionItems = new CompletionItem[0]; - } - - await requestContext.SendResult(completionItems); + Logger.Write(LogLevel.Normal, "HandleCompletionRequest"); + await Task.FromResult(true); } protected async Task HandleCompletionResolveRequest( CompletionItem completionItem, RequestContext requestContext) { - if (completionItem.Kind == CompletionItemKind.Function) - { - // Get the documentation for the function - CommandInfo commandInfo = - await CommandHelpers.GetCommandInfo( - completionItem.Label, - this.editorSession.SqlToolsContext); - - completionItem.Documentation = - await CommandHelpers.GetCommandSynopsis( - commandInfo, - this.editorSession.SqlToolsContext); - } - - // Send back the updated CompletionItem - await requestContext.SendResult(completionItem); + Logger.Write(LogLevel.Normal, "HandleCompletionResolveRequest"); + await Task.FromResult(true); } protected async Task HandleSignatureHelpRequest( TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentPosition.Uri); - - ParameterSetSignatures parameterSets = - await editorSession.LanguageService.FindParameterSetsInFile( - scriptFile, - textDocumentPosition.Position.Line + 1, - textDocumentPosition.Position.Character + 1); - - SignatureInformation[] signatures = null; - int? activeParameter = null; - int? activeSignature = 0; - - if (parameterSets != null) - { - signatures = - parameterSets - .Signatures - .Select(s => - { - return new SignatureInformation - { - Label = parameterSets.CommandName + " " + s.SignatureText, - Documentation = null, - Parameters = - s.Parameters - .Select(CreateParameterInfo) - .ToArray() - }; - }) - .ToArray(); - } - else - { - signatures = new SignatureInformation[0]; - } - - await requestContext.SendResult( - new SignatureHelp - { - Signatures = signatures, - ActiveParameter = activeParameter, - ActiveSignature = activeSignature - }); + Logger.Write(LogLevel.Normal, "HandleSignatureHelpRequest"); + await Task.FromResult(true); } protected async Task HandleDocumentHighlightRequest( TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentPosition.Uri); - - FindOccurrencesResult occurrencesResult = - editorSession.LanguageService.FindOccurrencesInFile( - scriptFile, - textDocumentPosition.Position.Line + 1, - textDocumentPosition.Position.Character + 1); - - DocumentHighlight[] documentHighlights = null; - - if (occurrencesResult != null) - { - documentHighlights = - occurrencesResult - .FoundOccurrences - .Select(o => - { - return new DocumentHighlight - { - Kind = DocumentHighlightKind.Write, // TODO: Which symbol types are writable? - Range = GetRangeFromScriptRegion(o.ScriptRegion) - }; - }) - .ToArray(); - } - else - { - documentHighlights = new DocumentHighlight[0]; - } - - await requestContext.SendResult(documentHighlights); + Logger.Write(LogLevel.Normal, "HandleDocumentHighlightRequest"); + await Task.FromResult(true); } protected async Task HandleHoverRequest( TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentPosition.Uri); - - SymbolDetails symbolDetails = - await editorSession - .LanguageService - .FindSymbolDetailsAtLocation( - scriptFile, - textDocumentPosition.Position.Line + 1, - textDocumentPosition.Position.Character + 1); - - List symbolInfo = new List(); - Range? symbolRange = null; - - if (symbolDetails != null) - { - symbolInfo.Add( - new MarkedString - { - Language = "SqlTools", - Value = symbolDetails.DisplayString - }); - - if (!string.IsNullOrEmpty(symbolDetails.Documentation)) - { - symbolInfo.Add( - new MarkedString - { - Language = "markdown", - Value = symbolDetails.Documentation - }); - } - - symbolRange = GetRangeFromScriptRegion(symbolDetails.SymbolReference.ScriptRegion); - } - - await requestContext.SendResult( - new Hover - { - Contents = symbolInfo.ToArray(), - Range = symbolRange - }); + Logger.Write(LogLevel.Normal, "HandleHoverRequest"); + await Task.FromResult(true); } protected async Task HandleDocumentSymbolRequest( TextDocumentIdentifier textDocumentIdentifier, RequestContext requestContext) { - ScriptFile scriptFile = - editorSession.Workspace.GetFile( - textDocumentIdentifier.Uri); - - FindOccurrencesResult foundSymbols = - editorSession.LanguageService.FindSymbolsInFile( - scriptFile); - - SymbolInformation[] symbols = null; - - string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath); - - if (foundSymbols != null) - { - symbols = - foundSymbols - .FoundOccurrences - .Select(r => - { - return new SymbolInformation - { - ContainerName = containerName, - Kind = GetSymbolKind(r.SymbolType), - Location = new Location - { - Uri = new Uri(r.FilePath).AbsolutePath, - Range = GetRangeFromScriptRegion(r.ScriptRegion) - }, - Name = GetDecoratedSymbolName(r) - }; - }) - .ToArray(); - } - else - { - symbols = new SymbolInformation[0]; - } - - await requestContext.SendResult(symbols); - } - - - private SymbolKind GetSymbolKind(SymbolType symbolType) - { - switch (symbolType) - { - case SymbolType.Configuration: - case SymbolType.Function: - case SymbolType.Workflow: - return SymbolKind.Function; - - default: - return SymbolKind.Variable; - } - } - - - private string GetDecoratedSymbolName(SymbolReference symbolReference) - { - string name = symbolReference.SymbolName; - - if (symbolReference.SymbolType == SymbolType.Configuration || - symbolReference.SymbolType == SymbolType.Function || - symbolReference.SymbolType == SymbolType.Workflow) - { - name += " { }"; - } - - return name; + Logger.Write(LogLevel.Normal, "HandleDocumentSymbolRequest"); + await Task.FromResult(true); } protected async Task HandleWorkspaceSymbolRequest( WorkspaceSymbolParams workspaceSymbolParams, RequestContext requestContext) { - var symbols = new List(); - - foreach (ScriptFile scriptFile in editorSession.Workspace.GetOpenedFiles()) - { - FindOccurrencesResult foundSymbols = - editorSession.LanguageService.FindSymbolsInFile( - scriptFile); - - // TODO: Need to compute a relative path that is based on common path for all workspace files - string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath); - - if (foundSymbols != null) - { - var matchedSymbols = - foundSymbols - .FoundOccurrences - .Where(r => IsQueryMatch(workspaceSymbolParams.Query, r.SymbolName)) - .Select(r => - { - return new SymbolInformation - { - ContainerName = containerName, - Kind = r.SymbolType == SymbolType.Variable ? SymbolKind.Variable : SymbolKind.Function, - Location = new Location - { - Uri = new Uri(r.FilePath).AbsoluteUri, - Range = GetRangeFromScriptRegion(r.ScriptRegion) - }, - Name = GetDecoratedSymbolName(r) - }; - }); - - symbols.AddRange(matchedSymbols); - } - } - - await requestContext.SendResult(symbols.ToArray()); - } - - private bool IsQueryMatch(string query, string symbolName) - { - return symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; - } - - protected Task HandleEvaluateRequest( - DebugAdapterMessages.EvaluateRequestArguments evaluateParams, - RequestContext requestContext) - { - // We don't await the result of the execution here because we want - // to be able to receive further messages while the current script - // is executing. This important in cases where the pipeline thread - // gets blocked by something in the script like a prompt to the user. - var executeTask = - this.editorSession.SqlToolsContext.ExecuteScriptString( - evaluateParams.Expression, - true, - true); - - // Return the execution result after the task completes so that the - // caller knows when command execution completed. - executeTask.ContinueWith( - (task) => - { - // Return an empty result since the result value is irrelevant - // for this request in the LanguageServer - return - requestContext.SendResult( - new DebugAdapterMessages.EvaluateResponseBody - { - Result = "", - VariablesReference = 0 - }); - }); - - return Task.FromResult(true); - } - - #endregion - - #region Event Handlers - - private async void SqlToolsContext_OutputWritten(object sender, OutputWrittenEventArgs e) - { - // Queue the output for writing - await this.outputDebouncer.Invoke(e); - } - - private async void ExtensionService_ExtensionAdded(object sender, EditorCommand e) - { - await this.SendEvent( - ExtensionCommandAddedNotification.Type, - new ExtensionCommandAddedNotification - { - Name = e.Name, - DisplayName = e.DisplayName - }); - } - - private async void ExtensionService_ExtensionUpdated(object sender, EditorCommand e) - { - await this.SendEvent( - ExtensionCommandUpdatedNotification.Type, - new ExtensionCommandUpdatedNotification - { - Name = e.Name, - }); - } - - private async void ExtensionService_ExtensionRemoved(object sender, EditorCommand e) - { - await this.SendEvent( - ExtensionCommandRemovedNotification.Type, - new ExtensionCommandRemovedNotification - { - Name = e.Name, - }); - } - - - #endregion -#endif - #region Helper Methods - - private static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion) - { - return new Range - { - Start = new Position - { - Line = scriptRegion.StartLineNumber - 1, - Character = scriptRegion.StartColumnNumber - 1 - }, - End = new Position - { - Line = scriptRegion.EndLineNumber - 1, - Character = scriptRegion.EndColumnNumber - 1 - } - }; - } - - 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 - }; - } - -#if false - 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) - { - // TODO: Catch a more specific exception! - 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. - // TODO: Is there a better way to do this? - existingRequestCancellation = new CancellationTokenSource(); - Task.Factory.StartNew( - () => - DelayThenInvokeDiagnostics( - 750, - filesToAnalyze, - editorSession, - eventContext, - existingRequestCancellation.Token), - CancellationToken.None, - TaskCreationOptions.None, - TaskScheduler.Default); - - return Task.FromResult(true); - } - - 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.AnalysisService != null) - { - Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath); - - semanticMarkers = - editorSession.AnalysisService.GetSemanticMarkers( - scriptFile); - - Logger.Write(LogLevel.Verbose, "Analysis complete."); - } - else - { - // Semantic markers aren't available if the AnalysisService - // isn't available - semanticMarkers = new ScriptFileMarker[0]; - } - - var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers); - - await PublishScriptDiagnostics( - scriptFile, - semanticMarkers, - eventContext); - } - } - - - private static async Task PublishScriptDiagnostics( - ScriptFile scriptFile, - ScriptFileMarker[] semanticMarkers, - EventContext eventContext) - { - var allMarkers = scriptFile.SyntaxMarkers.Concat(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() - }); - } - - 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 - } - } - }; - } - - private static CompletionItemKind MapCompletionKind(CompletionType completionType) - { - switch (completionType) - { - case CompletionType.Command: - return CompletionItemKind.Function; - - case CompletionType.Method: - return CompletionItemKind.Method; - - case CompletionType.Variable: - case CompletionType.ParameterName: - return CompletionItemKind.Variable; - - case CompletionType.Path: - return CompletionItemKind.File; - - default: - return CompletionItemKind.Text; - } - } - - private static CompletionItem CreateCompletionItem( - CompletionDetails completionDetails, - BufferRange completionRange, - int sortIndex) - { - string detailString = null; - string documentationString = null; - - if ((completionDetails.CompletionType == CompletionType.Variable) || - (completionDetails.CompletionType == CompletionType.ParameterName)) - { - // Look for type encoded in the tooltip for parameters and variables. - // Display SqlTools type names in [] to be consistent with SqlTools syntax - // and now the debugger displays type names. - var matches = Regex.Matches(completionDetails.ToolTipText, @"^(\[.+\])"); - if ((matches.Count > 0) && (matches[0].Groups.Count > 1)) - { - detailString = matches[0].Groups[1].Value; - } - } - else if ((completionDetails.CompletionType == CompletionType.Method) || - (completionDetails.CompletionType == CompletionType.Property)) - { - // We have a raw signature for .NET members, heck let's display it. It's - // better than nothing. - documentationString = completionDetails.ToolTipText; - } - else if (completionDetails.CompletionType == CompletionType.Command) - { - // For Commands, let's extract the resolved command or the path for an exe - // from the ToolTipText - if there is any ToolTipText. - if (completionDetails.ToolTipText != null) - { - // Fix for #240 - notepad++.exe in tooltip text caused regex parser to throw. - string escapedToolTipText = Regex.Escape(completionDetails.ToolTipText); - - // Don't display ToolTipText if it is the same as the ListItemText. - // Reject command syntax ToolTipText - it's too much to display as a detailString. - if (!completionDetails.ListItemText.Equals( - completionDetails.ToolTipText, - StringComparison.OrdinalIgnoreCase) && - !Regex.IsMatch(completionDetails.ToolTipText, - @"^\s*" + escapedToolTipText + @"\s+\[")) - { - detailString = completionDetails.ToolTipText; - } - } - } - - // We want a special "sort order" for parameters that is not lexicographical. - // Fortunately, SqlTools returns parameters in the preferred sort order by - // default (with common params at the end). We just need to make sure the default - // order also be the lexicographical order which we do by prefixig the ListItemText - // with a leading 0's four digit index. This would not sort correctly for a list - // > 999 parameters but surely we won't have so many items in the "parameter name" - // completion list. Technically we don't need the ListItemText at all but it may come - // in handy during debug. - var sortText = (completionDetails.CompletionType == CompletionType.ParameterName) - ? $"{sortIndex:D3}{completionDetails.ListItemText}" - : null; - - return new CompletionItem - { - InsertText = completionDetails.CompletionText, - Label = completionDetails.ListItemText, - Kind = MapCompletionKind(completionDetails.CompletionType), - Detail = detailString, - Documentation = documentationString, - SortText = sortText, - TextEdit = new TextEdit - { - NewText = completionDetails.CompletionText, - Range = new Range - { - Start = new Position - { - Line = completionRange.Start.Line - 1, - Character = completionRange.Start.Column - 1 - }, - End = new Position - { - Line = completionRange.End.Line - 1, - Character = completionRange.End.Column - 1 - } - } - } - }; - } -#endif - - 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; - } - } - -#if false - private static ParameterInformation CreateParameterInfo(ParameterInfo parameterInfo) - { - return new ParameterInformation - { - Label = parameterInfo.Name, - Documentation = string.Empty - }; - } -#endif - - #endregion + Logger.Write(LogLevel.Normal, "HandleWorkspaceSymbolRequest"); + await Task.FromResult(true); + } } } - diff --git a/ServiceHost/Server/LanguageServerSettings.cs b/ServiceHost/Server/LanguageServerSettings.cs index 5e9421b6..be09984a 100644 --- a/ServiceHost/Server/LanguageServerSettings.cs +++ b/ServiceHost/Server/LanguageServerSettings.cs @@ -28,6 +28,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server } } } + public class ScriptAnalysisSettings { @@ -77,6 +78,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server } } + public class LanguageServerSettingsWrapper { // NOTE: This property is capitalized as 'SqlTools' because the diff --git a/ServiceHost/Server/OutputDebouncer.cs b/ServiceHost/Server/OutputDebouncer.cs deleted file mode 100644 index d80673f7..00000000 --- a/ServiceHost/Server/OutputDebouncer.cs +++ /dev/null @@ -1,102 +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.DebugAdapter; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Microsoft.SqlTools.EditorServices.Utility; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Server -{ - /// - /// Throttles output written via OutputEvents by batching all output - /// written within a short time window and writing it all out at once. - /// - internal class OutputDebouncer : AsyncDebouncer - { - #region Private Fields - - private IMessageSender messageSender; - private bool currentOutputIsError = false; - private string currentOutputString = null; - - #endregion - - #region Constants - - // Set a really short window for output flushes. This - // gives the appearance of fast output without the crushing - // overhead of sending an OutputEvent for every single line - // written. At this point it seems that around 10-20 lines get - // batched for each flush when Get-Process is called. - public const int OutputFlushInterval = 200; - - #endregion - - #region Constructors - - public OutputDebouncer(IMessageSender messageSender) - : base(OutputFlushInterval, false) - { - this.messageSender = messageSender; - } - - #endregion - - #region Private Methods - - protected override async Task OnInvoke(OutputWrittenEventArgs output) - { - bool outputIsError = output.OutputType == OutputType.Error; - - if (this.currentOutputIsError != outputIsError) - { - if (this.currentOutputString != null) - { - // Flush the output - await this.OnFlush(); - } - - this.currentOutputString = string.Empty; - this.currentOutputIsError = outputIsError; - } - - // Output string could be null if the last output was already flushed - if (this.currentOutputString == null) - { - this.currentOutputString = string.Empty; - } - - // Add to string (and include newline) - this.currentOutputString += - output.OutputText + - (output.IncludeNewLine ? - System.Environment.NewLine : - string.Empty); - } - - protected override async Task OnFlush() - { - // Only flush output if there is some to flush - if (this.currentOutputString != null) - { - // Send an event for the current output - await this.messageSender.SendEvent( - OutputEvent.Type, - new OutputEventBody - { - Output = this.currentOutputString, - Category = (this.currentOutputIsError) ? "stderr" : "stdout" - }); - - // Clear the output string for the next batch - this.currentOutputString = null; - } - } - - #endregion - } -} - diff --git a/ServiceHost/Server/PromptHandlers.cs b/ServiceHost/Server/PromptHandlers.cs deleted file mode 100644 index 7af7a88c..00000000 --- a/ServiceHost/Server/PromptHandlers.cs +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#if false -using System; -using Microsoft.SqlTools.EditorServices.Console; -using Microsoft.SqlTools.EditorServices.Protocol.Messages; -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Microsoft.SqlTools.EditorServices.Utility; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Protocol.Server -{ - internal class ProtocolPromptHandlerContext : IPromptHandlerContext - { - private IMessageSender messageSender; - private ConsoleService consoleService; - - public ProtocolPromptHandlerContext( - IMessageSender messageSender, - ConsoleService consoleService) - { - this.messageSender = messageSender; - this.consoleService = consoleService; - } - - public ChoicePromptHandler GetChoicePromptHandler() - { - return new ProtocolChoicePromptHandler( - this.messageSender, - this.consoleService); - } - - public InputPromptHandler GetInputPromptHandler() - { - return new ProtocolInputPromptHandler( - this.messageSender, - this.consoleService); - } - } - - internal class ProtocolChoicePromptHandler : ChoicePromptHandler - { - private IMessageSender messageSender; - private ConsoleService consoleService; - - public ProtocolChoicePromptHandler( - IMessageSender messageSender, - ConsoleService consoleService) - { - this.messageSender = messageSender; - this.consoleService = consoleService; - } - - protected override void ShowPrompt(PromptStyle promptStyle) - { - messageSender - .SendRequest( - ShowChoicePromptRequest.Type, - new ShowChoicePromptRequest - { - Caption = this.Caption, - Message = this.Message, - Choices = this.Choices, - DefaultChoice = this.DefaultChoice - }, true) - .ContinueWith(HandlePromptResponse) - .ConfigureAwait(false); - } - - private void HandlePromptResponse( - Task responseTask) - { - if (responseTask.IsCompleted) - { - ShowChoicePromptResponse response = responseTask.Result; - - if (!response.PromptCancelled) - { - this.consoleService.ReceivePromptResponse( - response.ChosenItem, - false); - } - else - { - // Cancel the current prompt - this.consoleService.SendControlC(); - } - } - else - { - if (responseTask.IsFaulted) - { - // Log the error - Logger.Write( - LogLevel.Error, - "ShowChoicePrompt request failed with error:\r\n{0}", - responseTask.Exception.ToString()); - } - - // Cancel the current prompt - this.consoleService.SendControlC(); - } - } - } - - internal class ProtocolInputPromptHandler : ConsoleInputPromptHandler - { - private IMessageSender messageSender; - private ConsoleService consoleService; - - public ProtocolInputPromptHandler( - IMessageSender messageSender, - ConsoleService consoleService) - : base(consoleService) - { - this.messageSender = messageSender; - this.consoleService = consoleService; - } - - protected override void ShowErrorMessage(Exception e) - { - // Use default behavior for writing the error message - base.ShowErrorMessage(e); - } - - protected override void ShowPromptMessage(string caption, string message) - { - // Use default behavior for writing the prompt message - base.ShowPromptMessage(caption, message); - } - - protected override void ShowFieldPrompt(FieldDetails fieldDetails) - { - // Write the prompt to the console first so that there's a record - // of it occurring - base.ShowFieldPrompt(fieldDetails); - - messageSender - .SendRequest( - ShowInputPromptRequest.Type, - new ShowInputPromptRequest - { - Name = fieldDetails.Name, - Label = fieldDetails.Label - }, true) - .ContinueWith(HandlePromptResponse) - .ConfigureAwait(false); - } - - private void HandlePromptResponse( - Task responseTask) - { - if (responseTask.IsCompleted) - { - ShowInputPromptResponse response = responseTask.Result; - - if (!response.PromptCancelled) - { - this.consoleService.ReceivePromptResponse( - response.ResponseText, - true); - } - else - { - // Cancel the current prompt - this.consoleService.SendControlC(); - } - } - else - { - if (responseTask.IsFaulted) - { - // Log the error - Logger.Write( - LogLevel.Error, - "ShowInputPrompt request failed with error:\r\n{0}", - responseTask.Exception.ToString()); - } - - // Cancel the current prompt - this.consoleService.SendControlC(); - } - } - } -} - -#endif \ No newline at end of file diff --git a/ServiceHost/Utility/AsyncDebouncer.cs b/ServiceHost/Utility/AsyncDebouncer.cs deleted file mode 100644 index 86d05a2b..00000000 --- a/ServiceHost/Utility/AsyncDebouncer.cs +++ /dev/null @@ -1,169 +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 System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.EditorServices.Utility -{ - /// - /// Restricts the invocation of an operation to a specified time - /// interval. Can also cause previous requests to be cancelled - /// by new requests within that time window. Typically used for - /// buffering information for an operation or ensuring that an - /// operation only runs after some interval. - /// - /// The argument type for the Invoke method. - public abstract class AsyncDebouncer - { - #region Private Fields - - private int flushInterval; - private bool restartOnInvoke; - - private Task currentTimerTask; - private CancellationTokenSource timerCancellationSource; - - private AsyncLock asyncLock = new AsyncLock(); - - #endregion - - #region Public Methods - - /// - /// Creates a new instance of the AsyncDebouncer class with the - /// specified flush interval. If restartOnInvoke is true, any - /// calls to Invoke will cancel previous calls which have not yet - /// passed the flush interval. - /// - /// - /// A millisecond interval to use for flushing prior Invoke calls. - /// - /// - /// If true, Invoke calls will reset prior calls which haven't passed the flush interval. - /// - public AsyncDebouncer(int flushInterval, bool restartOnInvoke) - { - this.flushInterval = flushInterval; - this.restartOnInvoke = restartOnInvoke; - } - - /// - /// Invokes the debouncer with the given input. The debouncer will - /// wait for the specified interval before calling the Flush method - /// to complete the operation. - /// - /// - /// The argument for this implementation's Invoke method. - /// - /// A Task to be awaited until the Invoke is queued. - public async Task Invoke(TInvokeArgs invokeArgument) - { - using (await this.asyncLock.LockAsync()) - { - // Invoke the implementor - await this.OnInvoke(invokeArgument); - - // If there's no timer, start one - if (this.currentTimerTask == null) - { - this.StartTimer(); - } - else if (this.currentTimerTask != null && this.restartOnInvoke) - { - // Restart the existing timer - if (this.CancelTimer()) - { - this.StartTimer(); - } - } - } - } - - /// - /// Flushes the latest state regardless of the current interval. - /// An AsyncDebouncer MUST NOT invoke its own Flush method otherwise - /// deadlocks could occur. - /// - /// A Task to be awaited until Flush completes. - public async Task Flush() - { - using (await this.asyncLock.LockAsync()) - { - // Cancel the current timer - this.CancelTimer(); - - // Flush the current output - await this.OnFlush(); - } - } - - #endregion - - #region Abstract Methods - - /// - /// Implemented by the subclass to take the argument for the - /// future operation that will be performed by OnFlush. - /// - /// - /// The argument for this implementation's OnInvoke method. - /// - /// A Task to be awaited for the invoke to complete. - protected abstract Task OnInvoke(TInvokeArgs invokeArgument); - - /// - /// Implemented by the subclass to complete the current operation. - /// - /// A Task to be awaited for the operation to complete. - protected abstract Task OnFlush(); - - #endregion - - #region Private Methods - - private void StartTimer() - { - this.timerCancellationSource = new CancellationTokenSource(); - - this.currentTimerTask = - Task.Delay(this.flushInterval, this.timerCancellationSource.Token) - .ContinueWith( - t => - { - if (!t.IsCanceled) - { - return this.Flush(); - } - else - { - return Task.FromResult(true); - } - }); - } - - private bool CancelTimer() - { - if (this.timerCancellationSource != null) - { - // Attempt to cancel the timer task - this.timerCancellationSource.Cancel(); - } - - // Was the task cancelled? - bool wasCancelled = - this.currentTimerTask == null || - this.currentTimerTask.IsCanceled; - - // Clear the current task so that another may be created - this.currentTimerTask = null; - - return wasCancelled; - } - - #endregion - } -} - From 4ad506f6f272a00a461306f4b3253d37c3f9d2d7 Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Sat, 16 Jul 2016 01:14:12 -0700 Subject: [PATCH 2/4] Enable file change tracking with Workspace and EditorSession. Also include misc. clean-ups related to removing unneeded PowerShell Language Service code. --- ServiceHost/.vscode/launch.json | 2 +- ServiceHost/LanguageServer/TextDocument.cs | 15 +++ .../MessageProtocol/MessageDispatcher.cs | 2 +- .../Serializers/JsonRpcMessageSerializer.cs | 3 - .../Serializers/V8MessageSerializer.cs | 2 - ServiceHost/Server/LanguageServer.cs | 51 +++++++- ServiceHost/Session/EditorSession.cs | 64 ++++++++-- ServiceHost/Session/SqlToolsContext.cs | 25 ++++ ServiceHost/Workspace/ScriptFile.cs | 24 ++++ ServiceHost/Workspace/Workspace.cs | 109 +++++++++++------- 10 files changed, 237 insertions(+), 60 deletions(-) create mode 100644 ServiceHost/Session/SqlToolsContext.cs diff --git a/ServiceHost/.vscode/launch.json b/ServiceHost/.vscode/launch.json index ea4209f7..18ebbb27 100644 --- a/ServiceHost/.vscode/launch.json +++ b/ServiceHost/.vscode/launch.json @@ -18,7 +18,7 @@ "type": "coreclr", "request": "attach", "requireExactSource": false, - "processId": 14720 + "processId": 17264 } ] } \ No newline at end of file diff --git a/ServiceHost/LanguageServer/TextDocument.cs b/ServiceHost/LanguageServer/TextDocument.cs index 9b477c96..9f477374 100644 --- a/ServiceHost/LanguageServer/TextDocument.cs +++ b/ServiceHost/LanguageServer/TextDocument.cs @@ -61,12 +61,27 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer public class DidChangeTextDocumentParams : TextDocumentIdentifier { + public TextDocumentUriChangeEvent TextDocument { get; set; } + /// /// Gets or sets the list of changes to the document content. /// public TextDocumentChangeEvent[] ContentChanges { get; set; } } + public class TextDocumentUriChangeEvent + { + /// + /// Gets or sets the Uri of the changed text document + /// + public string Uri { get; set; } + + /// + /// Gets or sets the Version of the changed text document + /// + public int Version { get; set; } + } + public class TextDocumentChangeEvent { /// diff --git a/ServiceHost/MessageProtocol/MessageDispatcher.cs b/ServiceHost/MessageProtocol/MessageDispatcher.cs index 7d2d9c4c..21c179e2 100644 --- a/ServiceHost/MessageProtocol/MessageDispatcher.cs +++ b/ServiceHost/MessageProtocol/MessageDispatcher.cs @@ -18,7 +18,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol #region Fields private ChannelBase protocolChannel; - // private AsyncQueue messagesToWrite; + private AsyncContextThread messageLoopThread; private Dictionary> requestHandlers = diff --git a/ServiceHost/MessageProtocol/Serializers/JsonRpcMessageSerializer.cs b/ServiceHost/MessageProtocol/Serializers/JsonRpcMessageSerializer.cs index edf14712..fa1d1518 100644 --- a/ServiceHost/MessageProtocol/Serializers/JsonRpcMessageSerializer.cs +++ b/ServiceHost/MessageProtocol/Serializers/JsonRpcMessageSerializer.cs @@ -3,10 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System; namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers { diff --git a/ServiceHost/MessageProtocol/Serializers/V8MessageSerializer.cs b/ServiceHost/MessageProtocol/Serializers/V8MessageSerializer.cs index 4088a223..941e249a 100644 --- a/ServiceHost/MessageProtocol/Serializers/V8MessageSerializer.cs +++ b/ServiceHost/MessageProtocol/Serializers/V8MessageSerializer.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; diff --git a/ServiceHost/Server/LanguageServer.cs b/ServiceHost/Server/LanguageServer.cs index 4f7367a4..2f0f7963 100644 --- a/ServiceHost/Server/LanguageServer.cs +++ b/ServiceHost/Server/LanguageServer.cs @@ -8,17 +8,23 @@ 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; namespace Microsoft.SqlTools.EditorServices.Protocol.Server { public class LanguageServer : LanguageServerBase { + 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); } protected override void Initialize() @@ -43,6 +49,14 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.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); } @@ -80,11 +94,46 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server }); } + /// + /// Handles text document change events + /// + /// + /// + /// protected Task HandleDidChangeTextDocumentNotification( DidChangeTextDocumentParams textChangeParams, EventContext eventContext) { - Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification"); + 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.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.Normal, msg.ToString()); + + // // TODO: Get all recently edited files in the workspace + // this.RunScriptDiagnostics( + // changedFiles.ToArray(), + // editorSession, + // eventContext); + return Task.FromResult(true); } diff --git a/ServiceHost/Session/EditorSession.cs b/ServiceHost/Session/EditorSession.cs index 21c1b577..4b6c9a49 100644 --- a/ServiceHost/Session/EditorSession.cs +++ b/ServiceHost/Session/EditorSession.cs @@ -3,11 +3,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -// using Microsoft.SqlTools.EditorServices.Console; -// using Microsoft.SqlTools.EditorServices.Extensions; +using System; using Microsoft.SqlTools.EditorServices.Session; -// using Microsoft.SqlTools.EditorServices.Utility; -// using System.IO; namespace Microsoft.SqlTools.EditorServices { @@ -15,12 +12,8 @@ namespace Microsoft.SqlTools.EditorServices /// Manages a single session for all editor services. This /// includes managing all open script files for the session. /// - public class EditorSession + public class EditorSession : IDisposable { - public void StartSession(HostDetails hostDetails, ProfilePaths profilePaths) - { - } -#if false #region Properties /// @@ -33,6 +26,59 @@ namespace Microsoft.SqlTools.EditorServices /// public SqlToolsContext SqlToolsContext { get; private set; } + #endregion + + #region Public Methods + + /// + /// Starts the session using the provided IConsoleHost implementation + /// for the ConsoleService. + /// + /// + /// Provides details about the host application. + /// + /// + /// An object containing the profile paths for the session. + /// + public void StartSession(HostDetails hostDetails, ProfilePaths profilePaths) + { + // Initialize all services + this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths); + + + // this.LanguageService = new LanguageService(this.SqlToolsContext); + // this.DebugService = new DebugService(this.SqlToolsContext); + // this.ConsoleService = new ConsoleService(this.SqlToolsContext); + // this.ExtensionService = new ExtensionService(this.SqlToolsContext); + + // this.InstantiateAnalysisService(); + + // Create a workspace to contain open files + this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion); + } + + #endregion + + #region IDisposable Implementation + + /// + /// Disposes of any Runspaces that were created for the + /// services used in this session. + /// + public void Dispose() + { + } + + #endregion + + +#if false + #region Properties + + + + + /// /// Gets the LanguageService instance for this session. /// diff --git a/ServiceHost/Session/SqlToolsContext.cs b/ServiceHost/Session/SqlToolsContext.cs new file mode 100644 index 00000000..d8016afd --- /dev/null +++ b/ServiceHost/Session/SqlToolsContext.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; + +namespace Microsoft.SqlTools.EditorServices.Session +{ + public class SqlToolsContext + { + /// + /// Gets the PowerShell version of the current runspace. + /// + public Version SqlToolsVersion + { + get; private set; + } + + public SqlToolsContext(HostDetails hostDetails, ProfilePaths profilePaths) + { + + } + } +} diff --git a/ServiceHost/Workspace/ScriptFile.cs b/ServiceHost/Workspace/ScriptFile.cs index c68ecb96..7b041832 100644 --- a/ServiceHost/Workspace/ScriptFile.cs +++ b/ServiceHost/Workspace/ScriptFile.cs @@ -18,6 +18,30 @@ namespace Microsoft.SqlTools.EditorServices /// public class ScriptFile { + public ScriptFile( + string filePath, + string clientFilePath, + TextReader textReader, + Version SqlToolsVersion) + { + } + + /// + /// Creates a new ScriptFile instance with the specified file contents. + /// + /// The path at which the script file resides. + /// The path which the client uses to identify the file. + /// The initial contents of the script file. + /// The version of SqlTools for which the script is being parsed. + public ScriptFile( + string filePath, + string clientFilePath, + string initialBuffer, + Version SqlToolsVersion) + { + } + + #if false #region Private Fields diff --git a/ServiceHost/Workspace/Workspace.cs b/ServiceHost/Workspace/Workspace.cs index b8635ef2..6188a806 100644 --- a/ServiceHost/Workspace/Workspace.cs +++ b/ServiceHost/Workspace/Workspace.cs @@ -6,9 +6,9 @@ using Microsoft.SqlTools.EditorServices.Utility; using System; using System.Collections.Generic; -using System.Linq; using System.IO; using System.Text; +using System.Text.RegularExpressions; namespace Microsoft.SqlTools.EditorServices { @@ -18,8 +18,7 @@ namespace Microsoft.SqlTools.EditorServices /// public class Workspace { -#if false - #region Private Fields + #region Private Fields private Version SqlToolsVersion; private Dictionary workspaceFiles = new Dictionary(); @@ -93,6 +92,70 @@ namespace Microsoft.SqlTools.EditorServices return scriptFile; } + + private string ResolveFilePath(string filePath) + { + if (!IsPathInMemory(filePath)) + { + if (filePath.StartsWith(@"file://")) + { + // Client sent the path in URI format, extract the local path and trim + // any extraneous slashes + Uri fileUri = new Uri(filePath); + filePath = fileUri.LocalPath.TrimStart('/'); + } + + // Some clients send paths with UNIX-style slashes, replace those if necessary + filePath = filePath.Replace('/', '\\'); + + // Clients could specify paths with escaped space, [ and ] characters which .NET APIs + // will not handle. These paths will get appropriately escaped just before being passed + // into the SqlTools engine. + filePath = UnescapePath(filePath); + + // Get the absolute file path + filePath = Path.GetFullPath(filePath); + } + + Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath); + + return filePath; + } + + internal static bool IsPathInMemory(string filePath) + { + // When viewing SqlTools files in the Git diff viewer, VS Code + // sends the contents of the file at HEAD with a URI that starts + // with 'inmemory'. Untitled files which have been marked of + // type SqlTools have a path starting with 'untitled'. + return + filePath.StartsWith("inmemory") || + filePath.StartsWith("untitled"); + } + + /// + /// Unescapes any escaped [, ] or space characters. Typically use this before calling a + /// .NET API that doesn't understand PowerShell escaped chars. + /// + /// The path to unescape. + /// The path with the ` character before [, ] and spaces removed. + public static string UnescapePath(string path) + { + if (!path.Contains("`")) + { + return path; + } + + return Regex.Replace(path, @"`(?=[ \[\]])", ""); + } + + #endregion + +#if false + + + #region Public Methods + /// /// Gets a new ScriptFile instance which is identified by the given file @@ -222,46 +285,6 @@ namespace Microsoft.SqlTools.EditorServices } } - private string ResolveFilePath(string filePath) - { - if (!IsPathInMemory(filePath)) - { - if (filePath.StartsWith(@"file://")) - { - // Client sent the path in URI format, extract the local path and trim - // any extraneous slashes - Uri fileUri = new Uri(filePath); - filePath = fileUri.LocalPath.TrimStart('/'); - } - - // Some clients send paths with UNIX-style slashes, replace those if necessary - filePath = filePath.Replace('/', '\\'); - - // Clients could specify paths with escaped space, [ and ] characters which .NET APIs - // will not handle. These paths will get appropriately escaped just before being passed - // into the SqlTools engine. - filePath = SqlToolsContext.UnescapePath(filePath); - - // Get the absolute file path - filePath = Path.GetFullPath(filePath); - } - - Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath); - - return filePath; - } - - internal static bool IsPathInMemory(string filePath) - { - // When viewing SqlTools files in the Git diff viewer, VS Code - // sends the contents of the file at HEAD with a URI that starts - // with 'inmemory'. Untitled files which have been marked of - // type SqlTools have a path starting with 'untitled'. - return - filePath.StartsWith("inmemory") || - filePath.StartsWith("untitled"); - } - private string GetBaseFilePath(string filePath) { if (IsPathInMemory(filePath)) From ee664949c506fe00b2a59a59d5eb5b7c0bd6667a Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Sat, 16 Jul 2016 02:37:49 -0700 Subject: [PATCH 3/4] Additional code cleanup following initial check-in. Enable more ScriptFile code and hook in stub for error parsing. --- ServiceHost/Server/LanguageServer.cs | 236 +++++++++++++++++++++- ServiceHost/Session/EditorSession.cs | 4 - ServiceHost/Workspace/BufferPosition.cs | 1 - ServiceHost/Workspace/FilePosition.cs | 10 +- ServiceHost/Workspace/ScriptFile.cs | 48 +---- ServiceHost/Workspace/ScriptFileMarker.cs | 62 ------ ServiceHost/Workspace/Workspace.cs | 88 +------- 7 files changed, 231 insertions(+), 218 deletions(-) diff --git a/ServiceHost/Server/LanguageServer.cs b/ServiceHost/Server/LanguageServer.cs index 2f0f7963..7386d71f 100644 --- a/ServiceHost/Server/LanguageServer.cs +++ b/ServiceHost/Server/LanguageServer.cs @@ -10,11 +10,18 @@ using System.Threading.Tasks; using Microsoft.SqlTools.EditorServices.Utility; using System.Collections.Generic; using System.Text; +using System.Threading; +using System.Linq; namespace Microsoft.SqlTools.EditorServices.Protocol.Server { + /// + /// SQL Tools VS Code Language Server request handler + /// public class LanguageServer : LanguageServerBase { + private static CancellationTokenSource existingRequestCancellation; + private EditorSession editorSession; /// @@ -118,21 +125,20 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri); - // changedFile.ApplyChange( - // GetFileChangeDetails( - // textChange.Range.Value, - // textChange.Text)); + changedFile.ApplyChange( + GetFileChangeDetails( + textChange.Range.Value, + textChange.Text)); - // changedFiles.Add(changedFile); + changedFiles.Add(changedFile); } Logger.Write(LogLevel.Normal, msg.ToString()); - // // TODO: Get all recently edited files in the workspace - // this.RunScriptDiagnostics( - // changedFiles.ToArray(), - // editorSession, - // eventContext); + this.RunScriptDiagnostics( + changedFiles.ToArray(), + editorSession, + eventContext); return Task.FromResult(true); } @@ -231,6 +237,214 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server { Logger.Write(LogLevel.Normal, "HandleWorkspaceSymbolRequest"); await Task.FromResult(true); - } + } + + 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) + // { + // // TODO: Catch a more specific exception! + // 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. + // TODO: Is there a better way to do this? + existingRequestCancellation = new CancellationTokenSource(); + Task.Factory.StartNew( + () => + DelayThenInvokeDiagnostics( + 750, + filesToAnalyze, + editorSession, + eventContext, + existingRequestCancellation.Token), + CancellationToken.None, + TaskCreationOptions.None, + TaskScheduler.Default); + + return Task.FromResult(true); + } + + + 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.AnalysisService != null) + // { + // Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath); + + // semanticMarkers = + // editorSession.AnalysisService.GetSemanticMarkers( + // scriptFile); + + // Logger.Write(LogLevel.Verbose, "Analysis complete."); + // } + // else + { + // Semantic markers aren't available if the AnalysisService + // isn't available + semanticMarkers = new ScriptFileMarker[0]; + // semanticMarkers = new ScriptFileMarker[1]; + // semanticMarkers[0] = new ScriptFileMarker() + // { + // Message = "Error message", + // Level = ScriptFileMarkerLevel.Error, + // ScriptRegion = new ScriptRegion() + // { + // File = scriptFile.FilePath, + // StartLineNumber = 2, + // StartColumnNumber = 2, + // StartOffset = 0, + // EndLineNumber = 4, + // EndColumnNumber = 10, + // EndOffset = 0 + // } + // }; + } + + await PublishScriptDiagnostics( + scriptFile, + semanticMarkers, + eventContext); + } + } + + 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() + }); + } + + 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 + } + } + }; + } + + 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; + } + } + + 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/ServiceHost/Session/EditorSession.cs b/ServiceHost/Session/EditorSession.cs index 4b6c9a49..310a44c8 100644 --- a/ServiceHost/Session/EditorSession.cs +++ b/ServiceHost/Session/EditorSession.cs @@ -75,10 +75,6 @@ namespace Microsoft.SqlTools.EditorServices #if false #region Properties - - - - /// /// Gets the LanguageService instance for this session. /// diff --git a/ServiceHost/Workspace/BufferPosition.cs b/ServiceHost/Workspace/BufferPosition.cs index 0a892f79..8f790d85 100644 --- a/ServiceHost/Workspace/BufferPosition.cs +++ b/ServiceHost/Workspace/BufferPosition.cs @@ -108,4 +108,3 @@ namespace Microsoft.SqlTools.EditorServices #endregion } } - diff --git a/ServiceHost/Workspace/FilePosition.cs b/ServiceHost/Workspace/FilePosition.cs index 89d915ee..2cb58745 100644 --- a/ServiceHost/Workspace/FilePosition.cs +++ b/ServiceHost/Workspace/FilePosition.cs @@ -11,14 +11,6 @@ namespace Microsoft.SqlTools.EditorServices /// public class FilePosition : BufferPosition { - public FilePosition( - ScriptFile scriptFile, - int line, - int column) - : base(line, column) - { - } -#if false #region Private Fields private ScriptFile scriptFile; @@ -112,7 +104,7 @@ namespace Microsoft.SqlTools.EditorServices } #endregion -#endif + } } diff --git a/ServiceHost/Workspace/ScriptFile.cs b/ServiceHost/Workspace/ScriptFile.cs index 7b041832..90d66244 100644 --- a/ServiceHost/Workspace/ScriptFile.cs +++ b/ServiceHost/Workspace/ScriptFile.cs @@ -8,8 +8,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -//using System.Management.Automation; -//using System.Management.Automation.Language; namespace Microsoft.SqlTools.EditorServices { @@ -18,34 +16,8 @@ namespace Microsoft.SqlTools.EditorServices /// public class ScriptFile { - public ScriptFile( - string filePath, - string clientFilePath, - TextReader textReader, - Version SqlToolsVersion) - { - } - - /// - /// Creates a new ScriptFile instance with the specified file contents. - /// - /// The path at which the script file resides. - /// The path which the client uses to identify the file. - /// The initial contents of the script file. - /// The version of SqlTools for which the script is being parsed. - public ScriptFile( - string filePath, - string clientFilePath, - string initialBuffer, - Version SqlToolsVersion) - { - } - - -#if false #region Private Fields - private Token[] scriptTokens; private Version SqlToolsVersion; #endregion @@ -121,23 +93,6 @@ namespace Microsoft.SqlTools.EditorServices private set; } - /// - /// Gets the ScriptBlockAst representing the parsed script contents. - /// - public ScriptBlockAst ScriptAst - { - get; - private set; - } - - /// - /// Gets the array of Tokens representing the parsed script contents. - /// - public Token[] ScriptTokens - { - get { return this.scriptTokens; } - } - /// /// Gets the array of filepaths dot sourced in this ScriptFile /// @@ -502,6 +457,7 @@ namespace Microsoft.SqlTools.EditorServices /// private void ParseFileContents() { +#if false ParseError[] parseErrors = null; // First, get the updated file range @@ -574,9 +530,9 @@ namespace Microsoft.SqlTools.EditorServices //Get all dot sourced referenced files and store them this.ReferencedFiles = AstOperations.FindDotSourcedIncludes(this.ScriptAst); +#endif } #endregion -#endif } } diff --git a/ServiceHost/Workspace/ScriptFileMarker.cs b/ServiceHost/Workspace/ScriptFileMarker.cs index fbe944d6..87c2576c 100644 --- a/ServiceHost/Workspace/ScriptFileMarker.cs +++ b/ServiceHost/Workspace/ScriptFileMarker.cs @@ -3,14 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.EditorServices.Utility; -using System; -//using System.Management.Automation.Language; - -#if ScriptAnalyzer -using Microsoft.Windows.SqlTools.ScriptAnalyzer.Generic; -#endif - namespace Microsoft.SqlTools.EditorServices { /// @@ -59,60 +51,6 @@ namespace Microsoft.SqlTools.EditorServices public ScriptRegion ScriptRegion { get; set; } #endregion - - #region Public Methods - -#if false - internal static ScriptFileMarker FromParseError( - ParseError parseError) - { - Validate.IsNotNull("parseError", parseError); - - return new ScriptFileMarker - { - Message = parseError.Message, - Level = ScriptFileMarkerLevel.Error, - ScriptRegion = ScriptRegion.Create(parseError.Extent) - }; - } -#endif - -#if ScriptAnalyzer - internal static ScriptFileMarker FromDiagnosticRecord( - DiagnosticRecord diagnosticRecord) - { - Validate.IsNotNull("diagnosticRecord", diagnosticRecord); - - return new ScriptFileMarker - { - Message = diagnosticRecord.Message, - Level = GetMarkerLevelFromDiagnosticSeverity(diagnosticRecord.Severity), - ScriptRegion = ScriptRegion.Create(diagnosticRecord.Extent) - }; - } - - private static ScriptFileMarkerLevel GetMarkerLevelFromDiagnosticSeverity( - DiagnosticSeverity diagnosticSeverity) - { - switch (diagnosticSeverity) - { - case DiagnosticSeverity.Information: - return ScriptFileMarkerLevel.Information; - case DiagnosticSeverity.Warning: - return ScriptFileMarkerLevel.Warning; - case DiagnosticSeverity.Error: - return ScriptFileMarkerLevel.Error; - default: - throw new ArgumentException( - string.Format( - "The provided DiagnosticSeverity value '{0}' is unknown.", - diagnosticSeverity), - "diagnosticSeverity"); - } - } -#endif - - #endregion } } diff --git a/ServiceHost/Workspace/Workspace.cs b/ServiceHost/Workspace/Workspace.cs index 6188a806..39e1d70f 100644 --- a/ServiceHost/Workspace/Workspace.cs +++ b/ServiceHost/Workspace/Workspace.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Text.RegularExpressions; +using System.Linq; namespace Microsoft.SqlTools.EditorServices { @@ -149,15 +150,7 @@ namespace Microsoft.SqlTools.EditorServices return Regex.Replace(path, @"`(?=[ \[\]])", ""); } - #endregion - -#if false - - - #region Public Methods - - - /// + /// /// Gets a new ScriptFile instance which is identified by the given file /// path and initially contains the given buffer contents. /// @@ -211,80 +204,6 @@ namespace Microsoft.SqlTools.EditorServices this.workspaceFiles.Remove(scriptFile.Id); } - /// - /// Gets all file references by recursively searching - /// through referenced files in a scriptfile - /// - /// Contains the details and contents of an open script file - /// A scriptfile array where the first file - /// in the array is the "root file" of the search - public ScriptFile[] ExpandScriptReferences(ScriptFile scriptFile) - { - Dictionary referencedScriptFiles = new Dictionary(); - List expandedReferences = new List(); - - // add original file so it's not searched for, then find all file references - referencedScriptFiles.Add(scriptFile.Id, scriptFile); - RecursivelyFindReferences(scriptFile, referencedScriptFiles); - - // remove original file from referened file and add it as the first element of the - // expanded referenced list to maintain order so the original file is always first in the list - referencedScriptFiles.Remove(scriptFile.Id); - expandedReferences.Add(scriptFile); - - if (referencedScriptFiles.Count > 0) - { - expandedReferences.AddRange(referencedScriptFiles.Values); - } - - return expandedReferences.ToArray(); - } - - #endregion - - #region Private Methods - - /// - /// Recusrively searches through referencedFiles in scriptFiles - /// and builds a Dictonary of the file references - /// - /// Details an contents of "root" script file - /// A Dictionary of referenced script files - private void RecursivelyFindReferences( - ScriptFile scriptFile, - Dictionary referencedScriptFiles) - { - // Get the base path of the current script for use in resolving relative paths - string baseFilePath = - GetBaseFilePath( - scriptFile.FilePath); - - ScriptFile referencedFile; - foreach (string referencedFileName in scriptFile.ReferencedFiles) - { - string resolvedScriptPath = - this.ResolveRelativeScriptPath( - baseFilePath, - referencedFileName); - - // Make sure file exists before trying to get the file - if (File.Exists(resolvedScriptPath)) - { - // Get the referenced file if it's not already in referencedScriptFiles - referencedFile = this.GetFile(resolvedScriptPath); - - // Normalize the resolved script path and add it to the - // referenced files list if it isn't there already - resolvedScriptPath = resolvedScriptPath.ToLower(); - if (!referencedScriptFiles.ContainsKey(resolvedScriptPath)) - { - referencedScriptFiles.Add(resolvedScriptPath, referencedFile); - RecursivelyFindReferences(referencedFile, referencedScriptFiles); - } - } - } - } - private string GetBaseFilePath(string filePath) { if (IsPathInMemory(filePath)) @@ -324,7 +243,6 @@ namespace Microsoft.SqlTools.EditorServices return combinedPath; } - #endregion -#endif + #endregion } } From f2a5ebd605beeda046772704941c5f039233ac39 Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Sat, 16 Jul 2016 10:45:27 -0700 Subject: [PATCH 4/4] Add configuration change notification event handler. Clean up code a bit more to remove unneeded code. Better integrate the diagnostic callback code. --- .../LanguageSupport/LanguageService.cs | 57 +++++ ServiceHost/Program.cs | 4 +- ServiceHost/Server/LanguageServer.cs | 219 ++++++++++++------ ServiceHost/Session/EditorSession.cs | 144 +----------- 4 files changed, 212 insertions(+), 212 deletions(-) create mode 100644 ServiceHost/LanguageSupport/LanguageService.cs diff --git a/ServiceHost/LanguageSupport/LanguageService.cs b/ServiceHost/LanguageSupport/LanguageService.cs new file mode 100644 index 00000000..3ab77697 --- /dev/null +++ b/ServiceHost/LanguageSupport/LanguageService.cs @@ -0,0 +1,57 @@ +// +// 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; + +namespace Microsoft.SqlTools.LanguageSupport +{ + /// + /// Main class for Language Service functionality + /// + public class LanguageService + { + /// + /// 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) + { + // the commented out snippet is an example of how to create a error marker + // semanticMarkers = new ScriptFileMarker[1]; + // semanticMarkers[0] = new ScriptFileMarker() + // { + // Message = "Error message", + // Level = ScriptFileMarkerLevel.Error, + // ScriptRegion = new ScriptRegion() + // { + // File = scriptFile.FilePath, + // StartLineNumber = 2, + // StartColumnNumber = 2, + // StartOffset = 0, + // EndLineNumber = 4, + // EndColumnNumber = 10, + // EndOffset = 0 + // } + // }; + return new ScriptFileMarker[0]; + } + } +} diff --git a/ServiceHost/Program.cs b/ServiceHost/Program.cs index 622a026c..6bfd0f24 100644 --- a/ServiceHost/Program.cs +++ b/ServiceHost/Program.cs @@ -18,7 +18,9 @@ namespace Microsoft.SqlTools.ServiceHost /// static void Main(string[] args) { - Logger.Initialize(); + // turn on Verbose logging during early development + // we need to switch to Normal when preparing for public preview + Logger.Initialize(minimumLogLevel: LogLevel.Verbose); Logger.Write(LogLevel.Normal, "Starting SQL Tools Service Host"); const string hostName = "SQL Tools Service Host"; diff --git a/ServiceHost/Server/LanguageServer.cs b/ServiceHost/Server/LanguageServer.cs index 7386d71f..d6719141 100644 --- a/ServiceHost/Server/LanguageServer.cs +++ b/ServiceHost/Server/LanguageServer.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; using System.Linq; +using System; namespace Microsoft.SqlTools.EditorServices.Protocol.Server { @@ -21,6 +22,8 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server public class LanguageServer : LanguageServerBase { private static CancellationTokenSource existingRequestCancellation; + + private LanguageServerSettings currentSettings = new LanguageServerSettings(); private EditorSession editorSession; @@ -34,6 +37,9 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server this.editorSession.StartSession(hostDetails, profilePaths); } + /// + /// Initialize the VS Code request/response callbacks + /// protected override void Initialize() { // Register all supported message types @@ -54,6 +60,9 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server this.SetRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest); } + /// + /// Handles the shutdown event for the Language Server + /// protected override async Task Shutdown() { Logger.Write(LogLevel.Normal, "Language service is shutting down..."); @@ -67,14 +76,20 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server await Task.FromResult(true); } + /// + /// Handles the initialization request + /// + /// + /// + /// protected async Task HandleInitializeRequest( InitializeRequest initializeParams, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification"); + Logger.Write(LogLevel.Verbose, "HandleDidChangeTextDocumentNotification"); // Grab the workspace path from the parameters - //editorSession.Workspace.WorkspacePath = initializeParams.RootPath; + editorSession.Workspace.WorkspacePath = initializeParams.RootPath; await requestContext.SendResult( new InitializeResult @@ -133,7 +148,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server changedFiles.Add(changedFile); } - Logger.Write(LogLevel.Normal, msg.ToString()); + Logger.Write(LogLevel.Verbose, msg.ToString()); this.RunScriptDiagnostics( changedFiles.ToArray(), @@ -147,7 +162,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server DidOpenTextDocumentNotification openParams, EventContext eventContext) { - Logger.Write(LogLevel.Normal, "HandleDidOpenTextDocumentNotification"); + Logger.Write(LogLevel.Verbose, "HandleDidOpenTextDocumentNotification"); return Task.FromResult(true); } @@ -155,15 +170,57 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentIdentifier closeParams, EventContext eventContext) { - Logger.Write(LogLevel.Normal, "HandleDidCloseTextDocumentNotification"); + 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.Normal, "HandleDidChangeConfigurationNotification"); + 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); } @@ -171,7 +228,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleDefinitionRequest"); + Logger.Write(LogLevel.Verbose, "HandleDefinitionRequest"); await Task.FromResult(true); } @@ -179,7 +236,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server ReferencesParams referencesParams, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleReferencesRequest"); + Logger.Write(LogLevel.Verbose, "HandleReferencesRequest"); await Task.FromResult(true); } @@ -187,7 +244,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleCompletionRequest"); + Logger.Write(LogLevel.Verbose, "HandleCompletionRequest"); await Task.FromResult(true); } @@ -195,7 +252,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server CompletionItem completionItem, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleCompletionResolveRequest"); + Logger.Write(LogLevel.Verbose, "HandleCompletionResolveRequest"); await Task.FromResult(true); } @@ -203,7 +260,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleSignatureHelpRequest"); + Logger.Write(LogLevel.Verbose, "HandleSignatureHelpRequest"); await Task.FromResult(true); } @@ -211,7 +268,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleDocumentHighlightRequest"); + Logger.Write(LogLevel.Verbose, "HandleDocumentHighlightRequest"); await Task.FromResult(true); } @@ -219,7 +276,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentPosition textDocumentPosition, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleHoverRequest"); + Logger.Write(LogLevel.Verbose, "HandleHoverRequest"); await Task.FromResult(true); } @@ -227,7 +284,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server TextDocumentIdentifier textDocumentIdentifier, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleDocumentSymbolRequest"); + Logger.Write(LogLevel.Verbose, "HandleDocumentSymbolRequest"); await Task.FromResult(true); } @@ -235,53 +292,57 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server WorkspaceSymbolParams workspaceSymbolParams, RequestContext requestContext) { - Logger.Write(LogLevel.Normal, "HandleWorkspaceSymbolRequest"); + Logger.Write(LogLevel.Verbose, "HandleWorkspaceSymbolRequest"); await Task.FromResult(true); } + /// + /// 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 (!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 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) - // { - // // TODO: Catch a more specific exception! - // Logger.Write( - // LogLevel.Error, - // string.Format( - // "Exception while cancelling analysis task:\n\n{0}", - // e.ToString())); + // 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; - // } + 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. - // TODO: Is there a better way to do this? existingRequestCancellation = new CancellationTokenSource(); Task.Factory.StartNew( () => @@ -298,7 +359,14 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server return Task.FromResult(true); } - + /// + /// Actually run the script diagnostics after waiting for some small delay + /// + /// + /// + /// + /// + /// private static async Task DelayThenInvokeDiagnostics( int delayMilliseconds, ScriptFile[] filesToAnalyze, @@ -329,37 +397,17 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server foreach (ScriptFile scriptFile in filesToAnalyze) { ScriptFileMarker[] semanticMarkers = null; - // if (editorSession.AnalysisService != null) - // { - // Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath); - - // semanticMarkers = - // editorSession.AnalysisService.GetSemanticMarkers( - // scriptFile); - - // Logger.Write(LogLevel.Verbose, "Analysis complete."); - // } - // else + 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]; - // semanticMarkers = new ScriptFileMarker[1]; - // semanticMarkers[0] = new ScriptFileMarker() - // { - // Message = "Error message", - // Level = ScriptFileMarkerLevel.Error, - // ScriptRegion = new ScriptRegion() - // { - // File = scriptFile.FilePath, - // StartLineNumber = 2, - // StartColumnNumber = 2, - // StartOffset = 0, - // EndLineNumber = 4, - // EndColumnNumber = 10, - // EndOffset = 0 - // } - // }; + semanticMarkers = new ScriptFileMarker[0]; } await PublishScriptDiagnostics( @@ -369,6 +417,12 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server } } + /// + /// Send the diagnostic results back to the host application + /// + /// + /// + /// private static async Task PublishScriptDiagnostics( ScriptFile scriptFile, ScriptFileMarker[] semanticMarkers, @@ -392,6 +446,11 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server }); } + /// + /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible + /// + /// + /// private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker) { return new Diagnostic @@ -415,6 +474,10 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server }; } + /// + /// Map ScriptFileMarker severity to Diagnostic severity + /// + /// private static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel markerLevel) { switch (markerLevel) @@ -433,10 +496,14 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server } } + /// + /// 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, diff --git a/ServiceHost/Session/EditorSession.cs b/ServiceHost/Session/EditorSession.cs index 310a44c8..3c592a8f 100644 --- a/ServiceHost/Session/EditorSession.cs +++ b/ServiceHost/Session/EditorSession.cs @@ -5,6 +5,7 @@ using System; using Microsoft.SqlTools.EditorServices.Session; +using Microsoft.SqlTools.LanguageSupport; namespace Microsoft.SqlTools.EditorServices { @@ -21,6 +22,12 @@ namespace Microsoft.SqlTools.EditorServices /// public Workspace Workspace { get; private set; } + /// + /// Gets or sets the Language Service + /// + /// + public LanguageService LanguageService { get; set; } + /// /// Gets the SqlToolsContext instance for this session. /// @@ -30,80 +37,6 @@ namespace Microsoft.SqlTools.EditorServices #region Public Methods - /// - /// Starts the session using the provided IConsoleHost implementation - /// for the ConsoleService. - /// - /// - /// Provides details about the host application. - /// - /// - /// An object containing the profile paths for the session. - /// - public void StartSession(HostDetails hostDetails, ProfilePaths profilePaths) - { - // Initialize all services - this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths); - - - // this.LanguageService = new LanguageService(this.SqlToolsContext); - // this.DebugService = new DebugService(this.SqlToolsContext); - // this.ConsoleService = new ConsoleService(this.SqlToolsContext); - // this.ExtensionService = new ExtensionService(this.SqlToolsContext); - - // this.InstantiateAnalysisService(); - - // Create a workspace to contain open files - this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion); - } - - #endregion - - #region IDisposable Implementation - - /// - /// Disposes of any Runspaces that were created for the - /// services used in this session. - /// - public void Dispose() - { - } - - #endregion - - -#if false - #region Properties - - /// - /// Gets the LanguageService instance for this session. - /// - public LanguageService LanguageService { get; private set; } - - /// - /// Gets the AnalysisService instance for this session. - /// - public AnalysisService AnalysisService { get; private set; } - - /// - /// Gets the DebugService instance for this session. - /// - public DebugService DebugService { get; private set; } - - /// - /// Gets the ConsoleService instance for this session. - /// - public ConsoleService ConsoleService { get; private set; } - - /// - /// Gets the ExtensionService instance for this session. - /// - public ExtensionService ExtensionService { get; private set; } - - #endregion - - #region Public Methods - /// /// Starts the session using the provided IConsoleHost implementation /// for the ConsoleService. @@ -119,59 +52,11 @@ namespace Microsoft.SqlTools.EditorServices // Initialize all services this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths); this.LanguageService = new LanguageService(this.SqlToolsContext); - this.DebugService = new DebugService(this.SqlToolsContext); - this.ConsoleService = new ConsoleService(this.SqlToolsContext); - this.ExtensionService = new ExtensionService(this.SqlToolsContext); - - this.InstantiateAnalysisService(); // Create a workspace to contain open files this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion); } - /// - /// Restarts the AnalysisService so it can be configured with a new settings file. - /// - /// Path to the settings file. - public void RestartAnalysisService(string settingsPath) - { - this.AnalysisService?.Dispose(); - InstantiateAnalysisService(settingsPath); - } - - internal void InstantiateAnalysisService(string settingsPath = null) - { - // Only enable the AnalysisService if the machine has SqlTools - // v5 installed. Script Analyzer works on earlier SqlTools - // versions but our hard dependency on their binaries complicates - // the deployment and assembly loading since we would have to - // conditionally load the binaries for v3/v4 support. This problem - // will be solved in the future by using Script Analyzer as a - // module rather than an assembly dependency. - if (this.SqlToolsContext.SqlToolsVersion.Major >= 5) - { - // AnalysisService will throw FileNotFoundException if - // Script Analyzer binaries are not included. - try - { - this.AnalysisService = new AnalysisService(this.SqlToolsContext.ConsoleHost, settingsPath); - } - catch (FileNotFoundException) - { - Logger.Write( - LogLevel.Warning, - "Script Analyzer binaries not found, AnalysisService will be disabled."); - } - } - else - { - Logger.Write( - LogLevel.Normal, - "Script Analyzer cannot be loaded due to unsupported SqlTools version " + - this.SqlToolsContext.SqlToolsVersion.ToString()); - } - } - #endregion #region IDisposable Implementation @@ -181,21 +66,10 @@ namespace Microsoft.SqlTools.EditorServices /// services used in this session. /// public void Dispose() - { - if (this.AnalysisService != null) - { - this.AnalysisService.Dispose(); - this.AnalysisService = null; - } - - if (this.SqlToolsContext != null) - { - this.SqlToolsContext.Dispose(); - this.SqlToolsContext = null; - } + { } #endregion -#endif + } }