diff --git a/PowerShellEditorServices.sln b/PowerShellEditorServices.sln
index e71a5d46f..4c4487ac4 100644
--- a/PowerShellEditorServices.sln
+++ b/PowerShellEditorServices.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.40629.0
+# Visual Studio 14
+VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F594E7FD-1E72-4E51-A496-B019C2BA3180}"
EndProject
diff --git a/appveyor.yml b/appveyor.yml
index 732f2c921..fa2b73f3a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,6 +7,14 @@ branches:
only:
- master
+# NOTE: If you need to debug a problem with the AppVeyor build, uncomment the
+# following two lines and push them to your PR branch. Once the next
+# build starts you will see RDP connection details written out to the
+# build console. **DON'T FORGET TO REMOVE THIS COMMIT BEFORE MERGING!**
+
+#init:
+#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+
assembly_info:
patch: true
file: '**\AssemblyInfo.*'
diff --git a/scripts/AddCopyrightHeaders.ps1 b/scripts/AddCopyrightHeaders.ps1
index a11756eb2..bd0c161c1 100644
--- a/scripts/AddCopyrightHeaders.ps1
+++ b/scripts/AddCopyrightHeaders.ps1
@@ -11,24 +11,30 @@ $copyrightHeaderString =
//
'@
-$srcPath = Resolve-Path $PSScriptRoot\..\src
-Push-Location $srcPath
+$global:updateCount = 0;
-$updateCount = 0;
-$allSourceFiles = Get-ChildItem $srcPath -Recurse -Filter *.cs | ?{ $_.FullName -notmatch "\\obj\\?" }
-
-foreach ($sourceFile in $allSourceFiles)
+function Add-CopyrightHeaders($basePath)
{
- $fileContent = (Get-Content $sourceFile.FullName -Raw).TrimStart()
+ Push-Location $basePath
+ $allSourceFiles = Get-ChildItem $basePath -Recurse -Filter *.cs | ?{ $_.FullName -notmatch "\\obj\\?" }
- if ($fileContent.StartsWith($copyrightHeaderString) -eq $false)
+ foreach ($sourceFile in $allSourceFiles)
{
- # Add the copyright header to the file
- Set-Content $sourceFile.FullName ($copyrightHeaderString + "`r`n`r`n" + $fileContent)
- Write-Output ("Updated {0}" -f (Resolve-Path $sourceFile.FullName -Relative))
+ $fileContent = (Get-Content $sourceFile.FullName -Raw).TrimStart()
+
+ if ($fileContent.StartsWith($copyrightHeaderString) -eq $false)
+ {
+ # Add the copyright header to the file
+ Set-Content $sourceFile.FullName ($copyrightHeaderString + "`r`n`r`n" + $fileContent)
+ Write-Output ("Updated {0}" -f (Resolve-Path $sourceFile.FullName -Relative))
+ $global:updateCount++
+ }
}
+
+ Pop-Location
}
-Write-Output "`r`nDone, $updateCount files updated."
+Add-CopyrightHeaders(Resolve-Path $PSScriptRoot\..\src)
+Add-CopyrightHeaders(Resolve-Path $PSScriptRoot\..\test)
-Pop-Location
\ No newline at end of file
+Write-Output "`r`nDone, $global:updateCount file(s) updated."
diff --git a/src/PowerShellEditorServices.Host/IMessageProcessor.cs b/src/PowerShellEditorServices.Host/IMessageProcessor.cs
deleted file mode 100644
index e5e3dc7bf..000000000
--- a/src/PowerShellEditorServices.Host/IMessageProcessor.cs
+++ /dev/null
@@ -1,27 +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.PowerShell.EditorServices.Protocol.MessageProtocol;
-using System.Threading.Tasks;
-
-namespace Microsoft.PowerShell.EditorServices.Host
-{
- ///
- /// Provides an interface for classes that can process an incoming
- /// message of some type.
- ///
- public interface IMessageProcessor
- {
- ///
- /// Performs some action
- ///
- ///
- ///
- Task ProcessMessage(
- Message messageToProcess,
- EditorSession editorSession,
- MessageWriter messageWriter);
- }
-}
diff --git a/src/PowerShellEditorServices.Host/MessageLoop.cs b/src/PowerShellEditorServices.Host/MessageLoop.cs
deleted file mode 100644
index ced331b14..000000000
--- a/src/PowerShellEditorServices.Host/MessageLoop.cs
+++ /dev/null
@@ -1,207 +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.PowerShell.EditorServices.Protocol.DebugAdapter;
-using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
-using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
-using Microsoft.PowerShell.EditorServices.Utility;
-using Nito.AsyncEx;
-using System;
-using System.IO;
-using System.Management.Automation;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.PowerShell.EditorServices.Host
-{
- public class MessageLoop : IHost
- {
- #region Private Fields
-
- private Stream inputStream;
- private Stream outputStream;
- private bool runDebugAdapter;
- private IConsoleHost consoleHost;
- private EditorSession editorSession;
- private MessageReader messageReader;
- private MessageWriter messageWriter;
- private SynchronizationContext applicationSyncContext;
- private SynchronizationContext messageLoopSyncContext;
- private AsyncContextThread messageLoopThread;
-
- #endregion
-
- #region IHost Implementation
-
- string IHost.Name
- {
- get { throw new NotImplementedException(); }
- }
-
- Version IHost.Version
- {
- get { throw new NotImplementedException(); }
- }
-
- public void Start()
- {
- // Start the main message loop
- AsyncContext.Run((Func)this.StartMessageLoop);
- }
-
- #endregion
-
- #region Constructors
-
- public MessageLoop(bool runDebugAdapter)
- {
- this.runDebugAdapter = runDebugAdapter;
- }
-
- #endregion
-
- #region Private Methods
-
- private async Task StartMessageLoop()
- {
- // Hold on to the current synchronization context
- this.applicationSyncContext = SynchronizationContext.Current;
-
- // Start the message listener on another thread
- this.messageLoopThread = new AsyncContextThread(true);
- await this.messageLoopThread.Factory.Run(() => this.ListenForMessages());
- }
-
- async Task ListenForMessages()
- {
- this.messageLoopSyncContext = SynchronizationContext.Current;
-
- // Ensure that the console is using UTF-8 encoding
- System.Console.InputEncoding = Encoding.UTF8;
- System.Console.OutputEncoding = Encoding.UTF8;
-
- // Open the standard input/output streams
- this.inputStream = System.Console.OpenStandardInput();
- this.outputStream = System.Console.OpenStandardOutput();
-
- IMessageSerializer messageSerializer = null;
- IMessageProcessor messageProcessor = null;
-
- // Use a different serializer and message processor based
- // on whether this instance should host a language server
- // debug adapter.
- if (this.runDebugAdapter)
- {
- DebugAdapter debugAdapter = new DebugAdapter();
- debugAdapter.Initialize();
-
- messageProcessor = debugAdapter;
- messageSerializer = new V8MessageSerializer();
- }
- else
- {
- // Set up the LanguageServer
- LanguageServer languageServer = new LanguageServer();
- languageServer.Initialize();
-
- messageProcessor = languageServer;
- messageSerializer = new JsonRpcMessageSerializer();
- }
-
- // Set up the reader and writer
- this.messageReader =
- new MessageReader(
- this.inputStream,
- messageSerializer);
-
- this.messageWriter =
- new MessageWriter(
- this.outputStream,
- messageSerializer);
-
- // Set up the console host which will send events
- // through the MessageWriter
- this.consoleHost = new StdioConsoleHost(messageWriter);
-
- // Set up the PowerShell session
- this.editorSession = new EditorSession();
- this.editorSession.StartSession(this.consoleHost);
- this.editorSession.PowerShellContext.OutputWritten += powerShellContext_OutputWritten;
-
- if (this.runDebugAdapter)
- {
- // Attach to debugger events from the PowerShell session
- this.editorSession.DebugService.DebuggerStopped += DebugService_DebuggerStopped;
- }
-
- // Run the message loop
- bool isRunning = true;
- while (isRunning)
- {
- Message newMessage = null;
-
- try
- {
- // Read a message from stdin
- newMessage = await this.messageReader.ReadMessage();
- }
- catch (MessageParseException e)
- {
- // TODO: Write an error response
-
- Logger.Write(
- LogLevel.Error,
- "Could not parse a message that was received:\r\n\r\n" +
- e.ToString());
-
- // Continue the loop
- continue;
- }
-
- // Process the message
- await messageProcessor.ProcessMessage(
- newMessage,
- this.editorSession,
- this.messageWriter);
- }
- }
-
- void DebugService_DebuggerStopped(object sender, DebuggerStopEventArgs e)
- {
- // Push the write operation to the correct thread
- this.messageLoopSyncContext.Post(
- async (obj) =>
- {
- await this.messageWriter.WriteEvent(
- 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 = "breakpoint" // TODO: Change this based on context
- });
- }, null);
- }
-
- async void powerShellContext_OutputWritten(object sender, OutputWrittenEventArgs e)
- {
- await this.messageWriter.WriteEvent(
- OutputEvent.Type,
- new OutputEventBody
- {
- Output = e.OutputText + (e.IncludeNewLine ? "\r\n" : string.Empty),
- Category = (e.OutputType == OutputType.Error) ? "stderr" : "stdout"
- });
- }
-
- #endregion
- }
-}
diff --git a/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj b/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj
index fb6a09099..aa2dd9825 100644
--- a/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj
+++ b/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj
@@ -59,14 +59,8 @@
-
-
-
-
-
-
diff --git a/src/PowerShellEditorServices.Host/Program.cs b/src/PowerShellEditorServices.Host/Program.cs
index fd754a21c..b8be3ff07 100644
--- a/src/PowerShellEditorServices.Host/Program.cs
+++ b/src/PowerShellEditorServices.Host/Program.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using Microsoft.PowerShell.EditorServices.Protocol.Server;
using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Diagnostics;
@@ -39,6 +40,19 @@ static void Main(string[] args)
}
#endif
+ string logPath = null;
+ string logPathArgument =
+ args.FirstOrDefault(
+ arg =>
+ arg.StartsWith(
+ "/logPath:",
+ StringComparison.InvariantCultureIgnoreCase));
+
+ if (!string.IsNullOrEmpty(logPathArgument))
+ {
+ logPath = logPathArgument.Substring(9).Trim('"');
+ }
+
bool runDebugAdapter =
args.Any(
arg =>
@@ -50,25 +64,32 @@ static void Main(string[] args)
// Catch unhandled exceptions for logging purposes
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ ProtocolServer server = null;
if (runDebugAdapter)
{
- // TODO: Remove this behavior in the near future --
- // Create the debug service log in a separate file
- // so that there isn't a conflict with the default
- // log file.
- Logger.Initialize("DebugAdapter.log", LogLevel.Verbose);
+ logPath = logPath ?? "DebugAdapter.log";
+ server = new DebugAdapter();
}
else
{
- // Initialize the logger
- // TODO: Set the level based on command line parameter
- Logger.Initialize(minimumLogLevel: LogLevel.Verbose);
+ logPath = logPath ?? "EditorServices.log";
+ server = new LanguageServer();
}
+ // Start the logger with the specified log path
+ // TODO: Set the level based on command line parameter
+ Logger.Initialize(logPath, LogLevel.Verbose);
+
+ Logger.Write(LogLevel.Normal, "PowerShell Editor Services Host starting...");
+
+ // Start the server
+ server.Start();
Logger.Write(LogLevel.Normal, "PowerShell Editor Services Host started!");
- MessageLoop messageLoop = new MessageLoop(runDebugAdapter);
- messageLoop.Start();
+ // Wait for the server to finish
+ server.WaitForExit();
+
+ Logger.Write(LogLevel.Normal, "PowerShell Editor Services Host exited normally.");
}
static void CurrentDomain_UnhandledException(
diff --git a/src/PowerShellEditorServices.Host/StdioConsoleHost.cs b/src/PowerShellEditorServices.Host/StdioConsoleHost.cs
deleted file mode 100644
index be48a9065..000000000
--- a/src/PowerShellEditorServices.Host/StdioConsoleHost.cs
+++ /dev/null
@@ -1,110 +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.PowerShell.EditorServices.Protocol.MessageProtocol;
-using Microsoft.PowerShell.EditorServices.Utility;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.PowerShell.EditorServices.Host
-{
- public class StdioConsoleHost : IConsoleHost
- {
- #region Private Fields
-
- private MessageWriter messageWriter;
- private int currentReplEventSequence = 0;
- private TaskCompletionSource currentPromptChoiceTask;
-
- #endregion
-
- #region Constructors
-
- public StdioConsoleHost(MessageWriter messageWriter)
- {
- Validate.IsNotNull("messageWriter", messageWriter);
-
- this.messageWriter = messageWriter;
- }
-
- #endregion
-
- #region IConsoleHost Implementation
-
- Task IConsoleHost.PromptForChoice(
- string caption,
- string message,
- IEnumerable choices,
- int defaultChoice)
- {
- // NOTE: This code is held temporarily until a new model is
- // found for dealing with interactive prompts.
-
- //// Create and store a TaskCompletionSource that will be
- //// used to send the user's response back to the caller
- //this.currentPromptChoiceTask = new TaskCompletionSource();
- //this.currentReplEventSequence++;
-
- //this.messageWriter.WriteMessage(
- // new ReplPromptChoiceEvent
- // {
- // Body = new ReplPromptChoiceEventBody
- // {
- // Seq = this.currentReplEventSequence,
- // Caption = caption,
- // Message = message,
- // DefaultChoice = defaultChoice,
- // Choices =
- // choices
- // .Select(ReplPromptChoiceDetails.FromChoiceDescription)
- // .ToArray()
- // }
- // });
-
- //return this.currentPromptChoiceTask.Task;
-
- throw new NotImplementedException("This method is currently being refactored and is not available.");
- }
-
- void IConsoleHost.PromptForChoiceResult(
- int promptId,
- int choiceResult)
- {
- // TODO: Validate that prompt ID exists
- Validate.IsNotNull("currentPromptChoiceTask", this.currentPromptChoiceTask);
-
- this.currentPromptChoiceTask.SetResult(choiceResult);
- this.currentPromptChoiceTask = null;
- }
-
- void IConsoleHost.UpdateProgress(
- long sourceId,
- ProgressDetails progressDetails)
- {
- // TODO: Implement message for this
- }
-
- void IConsoleHost.ExitSession(int exitCode)
- {
- // TODO: Implement message for this
- }
-
- public void WriteOutput(
- string outputString,
- bool includeNewLine = true,
- OutputType outputType = OutputType.Normal,
- ConsoleColor foregroundColor = ConsoleColor.White,
- ConsoleColor backgroundColor = ConsoleColor.Black)
- {
- // This is taken care of elsewhere now. This interface will
- // be refactored out in the near future.
- }
-
- #endregion
- }
-}
diff --git a/src/PowerShellEditorServices.Protocol/Client/DebugAdapterClientBase.cs b/src/PowerShellEditorServices.Protocol/Client/DebugAdapterClientBase.cs
new file mode 100644
index 000000000..8b149e569
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Client/DebugAdapterClientBase.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Client
+{
+ public class DebugAdapterClient : ProtocolClient
+ {
+ public DebugAdapterClient(ChannelBase clientChannel)
+ : base(clientChannel, MessageProtocolType.DebugAdapter)
+ {
+ }
+
+ public Task LaunchScript(string scriptFilePath)
+ {
+ return this.SendRequest(
+ LaunchRequest.Type,
+ new LaunchRequestArguments
+ {
+ Program = scriptFilePath
+ });
+ }
+
+ protected override async Task OnStart()
+ {
+ // Initialize the debug adapter
+ await this.SendRequest(
+ InitializeRequest.Type,
+ new InitializeRequestArguments
+ {
+ LinesStartAt1 = true
+ });
+ }
+ }
+}
+
diff --git a/src/PowerShellEditorServices.Protocol/Client/LanguageClientBase.cs b/src/PowerShellEditorServices.Protocol/Client/LanguageClientBase.cs
new file mode 100644
index 000000000..c106fb59d
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Client/LanguageClientBase.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Client
+{
+ ///
+ /// Provides a base implementation for language server clients.
+ ///
+ public abstract class LanguageClientBase : ProtocolClient
+ {
+ ///
+ /// 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/src/PowerShellEditorServices.Protocol/Client/LanguageServiceClient.cs b/src/PowerShellEditorServices.Protocol/Client/LanguageServiceClient.cs
new file mode 100644
index 000000000..3cb65b07a
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Client/LanguageServiceClient.cs
@@ -0,0 +1,116 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Client
+{
+ public class LanguageServiceClient : LanguageClientBase
+ {
+ private Dictionary cachedDiagnostics =
+ new Dictionary();
+
+ public LanguageServiceClient(ChannelBase clientChannel)
+ : base(clientChannel)
+ {
+ }
+
+ protected override async Task Initialize()
+ {
+ // Add handlers for common events
+ this.SetEventHandler(PublishDiagnosticsNotification.Type, HandlePublishDiagnosticsEvent);
+
+ // Send the 'initialize' request and wait for the response
+ var initializeRequest = new InitializeRequest
+ {
+ RootPath = "",
+ Capabilities = new ClientCapabilities()
+ };
+
+ await 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/src/PowerShellEditorServices.Protocol/Client/ProtocolClient.cs b/src/PowerShellEditorServices.Protocol/Client/ProtocolClient.cs
new file mode 100644
index 000000000..01c66781d
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Client/ProtocolClient.cs
@@ -0,0 +1,190 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Client
+{
+ public class ProtocolClient
+ {
+ private bool isStarted;
+ private int currentMessageId;
+ private ChannelBase clientChannel;
+ private MessageProtocolType messageProtocolType;
+ private SynchronizationContext originalSynchronizationContext;
+
+ private Dictionary> pendingRequests =
+ new Dictionary>();
+
+ ///
+ /// Initializes an instance of the protocol client using the
+ /// specified channel for communication.
+ ///
+ /// The channel to use for communication with the server.
+ /// The type of message protocol used by the server.
+ public ProtocolClient(
+ ChannelBase clientChannel,
+ MessageProtocolType messageProtocolType)
+ {
+ this.clientChannel = clientChannel;
+ this.messageProtocolType = messageProtocolType;
+ }
+
+ ///
+ /// Starts the language server client and sends the Initialize method.
+ ///
+ /// A Task that can be awaited for initialization to complete.
+ public async Task Start()
+ {
+ if (!this.isStarted)
+ {
+ // Start the provided client channel
+ this.clientChannel.Start(this.messageProtocolType);
+
+ // Set the handler for any message responses that come back
+ this.clientChannel.MessageDispatcher.SetResponseHandler(this.HandleResponse);
+
+ // Listen for unhandled exceptions from the dispatcher
+ this.clientChannel.MessageDispatcher.UnhandledException += MessageDispatcher_UnhandledException;
+
+ // Notify implementation about client start
+ await this.OnStart();
+
+ // Client is now started
+ this.isStarted = true;
+ }
+ }
+
+ public async Task Stop()
+ {
+ if (this.isStarted)
+ {
+ // Stop the implementation first
+ await this.OnStop();
+
+ this.clientChannel.Stop();
+ this.isStarted = false;
+ }
+ }
+
+ ///
+ /// Sends a request to the server
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Task SendRequest(
+ RequestType requestType,
+ TParams requestParams)
+ {
+ return this.SendRequest(requestType, requestParams, true);
+ }
+
+ public async Task SendRequest(
+ RequestType requestType,
+ TParams requestParams,
+ bool waitForResponse)
+ {
+ this.currentMessageId++;
+
+ TaskCompletionSource responseTask = null;
+
+ if (waitForResponse)
+ {
+ responseTask = new TaskCompletionSource();
+ this.pendingRequests.Add(
+ this.currentMessageId.ToString(),
+ responseTask);
+ }
+
+ await this.clientChannel.MessageWriter.WriteRequest(
+ requestType,
+ requestParams,
+ this.currentMessageId);
+
+ if (responseTask != null)
+ {
+ var responseMessage = await responseTask.Task;
+
+ return
+ responseMessage.Contents != null ?
+ responseMessage.Contents.ToObject() :
+ default(TResult);
+ }
+ else
+ {
+ // TODO: Better default value here?
+ return default(TResult);
+ }
+ }
+
+ public async Task SendEvent(EventType eventType, TParams eventParams)
+ {
+ await this.clientChannel.MessageWriter.WriteMessage(
+ Message.Event(
+ eventType.MethodName,
+ JToken.FromObject(eventParams)));
+ }
+
+ public void SetEventHandler(
+ EventType eventType,
+ Func eventHandler)
+ {
+ this.clientChannel.MessageDispatcher.SetEventHandler(
+ eventType,
+ eventHandler,
+ false);
+ }
+
+ public void SetEventHandler(
+ EventType eventType,
+ Func eventHandler,
+ bool overrideExisting)
+ {
+ this.clientChannel.MessageDispatcher.SetEventHandler(
+ eventType,
+ eventHandler,
+ overrideExisting);
+ }
+
+ private void MessageDispatcher_UnhandledException(object sender, Exception e)
+ {
+ if (this.originalSynchronizationContext != null)
+ {
+ this.originalSynchronizationContext.Post(o => { throw e; }, null);
+ }
+ }
+
+ private void HandleResponse(Message responseMessage)
+ {
+ TaskCompletionSource pendingRequestTask = null;
+
+ if (this.pendingRequests.TryGetValue(responseMessage.Id, out pendingRequestTask))
+ {
+ pendingRequestTask.SetResult(responseMessage);
+ this.pendingRequests.Remove(responseMessage.Id);
+ }
+ }
+
+ protected virtual Task OnStart()
+ {
+ return Task.FromResult(true);
+ }
+
+ protected virtual Task OnStop()
+ {
+ return Task.FromResult(true);
+ }
+ }
+}
+
diff --git a/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs b/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs
index dde25ac05..4b8faa9c3 100644
--- a/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs
+++ b/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs
@@ -10,8 +10,8 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter
public class AttachRequest
{
public static readonly
- RequestType Type =
- RequestType.Create("attach");
+ RequestType Type =
+ RequestType.Create("attach");
}
public class AttachRequestArguments
diff --git a/src/PowerShellEditorServices.Protocol/DebugAdapter/ContinueRequest.cs b/src/PowerShellEditorServices.Protocol/DebugAdapter/ContinueRequest.cs
index 43b7191ef..5ee5b2ec9 100644
--- a/src/PowerShellEditorServices.Protocol/DebugAdapter/ContinueRequest.cs
+++ b/src/PowerShellEditorServices.Protocol/DebugAdapter/ContinueRequest.cs
@@ -10,8 +10,8 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter
public class ContinueRequest
{
public static readonly
- RequestType
+
+
+
+
@@ -86,7 +91,8 @@
-
+
+
@@ -94,30 +100,39 @@
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
+
+
diff --git a/src/PowerShellEditorServices.Host/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
similarity index 61%
rename from src/PowerShellEditorServices.Host/DebugAdapter.cs
rename to src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
index 87a252f97..a3fdaf683 100644
--- a/src/PowerShellEditorServices.Host/DebugAdapter.cs
+++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
@@ -5,124 +5,88 @@
using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using Microsoft.PowerShell.EditorServices.Protocol.Server;
using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Management.Automation;
using System.Threading.Tasks;
-namespace Microsoft.PowerShell.EditorServices.Host
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
{
- internal class DebugAdapter : IMessageProcessor
+ public class DebugAdapter : DebugAdapterBase
{
- private MessageDispatcher messageDispatcher;
+ private EditorSession editorSession;
- public DebugAdapter()
+ public DebugAdapter() : this(new StdioServerChannel())
{
- this.messageDispatcher = new MessageDispatcher();
}
- public void Initialize()
+ public DebugAdapter(ChannelBase serverChannel) : base(serverChannel)
{
- // Register all supported message types
-
- this.AddRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
- this.AddRequestHandler(LaunchRequest.Type, this.HandleLaunchRequest);
- this.AddRequestHandler(AttachRequest.Type, this.HandleAttachRequest);
- this.AddRequestHandler(DisconnectRequest.Type, this.HandleDisconnectRequest);
-
- this.AddRequestHandler(SetBreakpointsRequest.Type, this.HandleSetBreakpointsRequest);
- this.AddRequestHandler(SetExceptionBreakpointsRequest.Type, this.HandleSetExceptionBreakpointsRequest);
-
- this.AddRequestHandler(ContinueRequest.Type, this.HandleContinueRequest);
- this.AddRequestHandler(NextRequest.Type, this.HandleNextRequest);
- this.AddRequestHandler(StepInRequest.Type, this.HandleStepInRequest);
- this.AddRequestHandler(StepOutRequest.Type, this.HandleStepOutRequest);
- this.AddRequestHandler(PauseRequest.Type, this.HandlePauseRequest);
-
- this.AddRequestHandler(ThreadsRequest.Type, this.HandleThreadsRequest);
- this.AddRequestHandler(StackTraceRequest.Type, this.HandleStackTraceRequest);
- this.AddRequestHandler(ScopesRequest.Type, this.HandleScopesRequest);
- this.AddRequestHandler(VariablesRequest.Type, this.HandleVariablesRequest);
- this.AddRequestHandler(SourceRequest.Type, this.HandleSourceRequest);
- this.AddRequestHandler(EvaluateRequest.Type, this.HandleEvaluateRequest);
+ this.editorSession = new EditorSession();
+ this.editorSession.StartSession();
+ this.editorSession.DebugService.DebuggerStopped += this.DebugService_DebuggerStopped;
}
- public void AddRequestHandler(
- RequestType requestType,
- Func, Task> requestHandler)
+ protected override void Initialize()
{
- this.messageDispatcher.AddRequestHandler(
- requestType,
- requestHandler);
- }
+ // Register all supported message types
- public void AddEventHandler(
- EventType eventType,
- Func eventHandler)
- {
- this.messageDispatcher.AddEventHandler(
- eventType,
- eventHandler);
- }
-
- public async Task ProcessMessage(
- Message messageToProcess,
- EditorSession editorSession,
- MessageWriter messageWriter)
- {
- await this.messageDispatcher.DispatchMessage(
- messageToProcess,
- editorSession,
- messageWriter);
+ this.SetRequestHandler(LaunchRequest.Type, this.HandleLaunchRequest);
+ this.SetRequestHandler(AttachRequest.Type, this.HandleAttachRequest);
+ this.SetRequestHandler(DisconnectRequest.Type, this.HandleDisconnectRequest);
+
+ this.SetRequestHandler(SetBreakpointsRequest.Type, this.HandleSetBreakpointsRequest);
+ this.SetRequestHandler(SetExceptionBreakpointsRequest.Type, this.HandleSetExceptionBreakpointsRequest);
+
+ 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);
}
#region Built-in Message Handlers
- protected async Task HandleInitializeRequest(
- InitializeRequestArguments initializeParams,
- EditorSession editorSession,
- RequestContext requestContext)
- {
- // Send the Initialized event first so that we get breakpoints
- await requestContext.SendEvent(
- InitializedEvent.Type,
- null);
-
- // Now send the Initialize response to continue setup
- await requestContext.SendResult(new object());
- }
-
protected async Task HandleLaunchRequest(
LaunchRequestArguments launchParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
// Execute the given PowerShell script and send the response.
// Note that we aren't waiting for execution to complete here
// because the debugger could stop while the script executes.
- editorSession.PowerShellContext
- .ExecuteScriptAtPath(launchParams.Program)
- .ContinueWith(
- async (t) =>
- {
- Logger.Write(LogLevel.Verbose, "Execution completed, terminating...");
+ Task executeTask =
+ editorSession.PowerShellContext
+ .ExecuteScriptAtPath(launchParams.Program)
+ .ContinueWith(
+ async (t) =>
+ {
+ Logger.Write(LogLevel.Verbose, "Execution completed, terminating...");
- await requestContext.SendEvent(
- TerminatedEvent.Type,
- null);
+ await requestContext.SendEvent(
+ TerminatedEvent.Type,
+ null);
- // TODO: Find a way to exit more gracefully!
- Environment.Exit(0);
- });
+ // Stop the server
+ this.Stop();
+ });
await requestContext.SendResult(null);
}
protected Task HandleAttachRequest(
AttachRequestArguments attachParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
// TODO: Implement this once we support attaching to processes
throw new NotImplementedException();
@@ -130,8 +94,7 @@ protected Task HandleAttachRequest(
protected Task HandleDisconnectRequest(
object disconnectParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
EventHandler handler = null;
@@ -143,8 +106,8 @@ protected Task HandleDisconnectRequest(
await requestContext.SendResult(null);
editorSession.PowerShellContext.SessionStateChanged -= handler;
- // TODO: Find a way to exit more gracefully!
- Environment.Exit(0);
+ // Stop the server
+ this.Stop();
}
};
@@ -156,8 +119,7 @@ protected Task HandleDisconnectRequest(
protected async Task HandleSetBreakpointsRequest(
SetBreakpointsRequestArguments setBreakpointsParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -173,15 +135,14 @@ await requestContext.SendResult(
{
Breakpoints =
breakpoints
- .Select(Breakpoint.Create)
+ .Select(Protocol.DebugAdapter.Breakpoint.Create)
.ToArray()
});
}
protected async Task HandleSetExceptionBreakpointsRequest(
SetExceptionBreakpointsRequestArguments setExceptionBreakpointsParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
// TODO: Handle this appropriately
@@ -190,8 +151,7 @@ protected async Task HandleSetExceptionBreakpointsRequest(
protected async Task HandleContinueRequest(
object continueParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
editorSession.DebugService.Continue();
@@ -200,8 +160,7 @@ protected async Task HandleContinueRequest(
protected async Task HandleNextRequest(
object nextParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
editorSession.DebugService.StepOver();
@@ -210,8 +169,7 @@ protected async Task HandleNextRequest(
protected Task HandlePauseRequest(
object pauseParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
editorSession.DebugService.Break();
@@ -221,8 +179,7 @@ protected Task HandlePauseRequest(
protected async Task HandleStepInRequest(
object stepInParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
editorSession.DebugService.StepIn();
@@ -231,8 +188,7 @@ protected async Task HandleStepInRequest(
protected async Task HandleStepOutRequest(
object stepOutParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
editorSession.DebugService.StepOut();
@@ -241,8 +197,7 @@ protected async Task HandleStepOutRequest(
protected async Task HandleThreadsRequest(
object threadsParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
await requestContext.SendResult(
new ThreadsResponseBody
@@ -261,8 +216,7 @@ await requestContext.SendResult(
protected async Task HandleStackTraceRequest(
StackTraceRequestArguments stackTraceParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
StackFrameDetails[] stackFrames =
editorSession.DebugService.GetStackFrames();
@@ -288,8 +242,7 @@ await requestContext.SendResult(
protected async Task HandleScopesRequest(
ScopesRequestArguments scopesParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
VariableScope[] variableScopes =
editorSession.DebugService.GetVariableScopes(
@@ -307,8 +260,7 @@ await requestContext.SendResult(
protected async Task HandleVariablesRequest(
VariablesRequestArguments variablesParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
VariableDetailsBase[] variables =
editorSession.DebugService.GetVariables(
@@ -336,8 +288,7 @@ protected async Task HandleVariablesRequest(
protected Task HandleSourceRequest(
SourceRequestArguments sourceParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
// TODO: Implement this message. For now, doesn't seem to
// be a problem that it's missing.
@@ -347,8 +298,7 @@ protected Task HandleSourceRequest(
protected async Task HandleEvaluateRequest(
EvaluateRequestArguments evaluateParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
VariableDetails result =
await editorSession.DebugService.EvaluateExpression(
@@ -375,6 +325,27 @@ await requestContext.SendResult(
}
#endregion
+
+ #region Event Handlers
+
+ async void DebugService_DebuggerStopped(object sender, DebuggerStopEventArgs e)
+ {
+ 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 = "breakpoint" // TODO: Change this based on context
+ });
+ }
+
+ #endregion
}
}
diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapterBase.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapterBase.cs
new file mode 100644
index 000000000..c8492c2f4
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapterBase.cs
@@ -0,0 +1,63 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
+{
+ public abstract class DebugAdapterBase : ProtocolServer
+ {
+ 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 void OnStart()
+ {
+ // Register handlers for server lifetime messages
+ this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
+
+ // Initialize the implementation class
+ this.Initialize();
+ }
+
+ protected override void OnStop()
+ {
+ this.Shutdown();
+ }
+
+ private async Task HandleInitializeRequest(
+ object shutdownParams,
+ RequestContext requestContext)
+ {
+ // Send the Initialized event first so that we get breakpoints
+ await requestContext.SendEvent(
+ InitializedEvent.Type,
+ null);
+
+ // Now send the Initialize response to continue setup
+ await requestContext.SendResult(new object());
+ }
+ }
+}
+
diff --git a/src/PowerShellEditorServices.Host/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs
similarity index 88%
rename from src/PowerShellEditorServices.Host/LanguageServer.cs
rename to src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs
index 5751a767d..704380a64 100644
--- a/src/PowerShellEditorServices.Host/LanguageServer.cs
+++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs
@@ -3,99 +3,81 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-using DebugAdapterMessages = Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
using Microsoft.PowerShell.EditorServices.Utility;
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
-using System.IO;
+using DebugAdapterMessages = Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
-namespace Microsoft.PowerShell.EditorServices.Host
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
{
- internal class LanguageServer : IMessageProcessor
+ public class LanguageServer : LanguageServerBase
{
private static CancellationTokenSource existingRequestCancellation;
- private MessageDispatcher messageDispatcher;
+ private EditorSession editorSession;
private LanguageServerSettings currentSettings = new LanguageServerSettings();
- public LanguageServer()
+ public LanguageServer() : this(new StdioServerChannel())
{
- this.messageDispatcher = new MessageDispatcher();
}
- public void Initialize()
+ public LanguageServer(ChannelBase serverChannel) : base(serverChannel)
{
- // Register all supported message types
-
- this.AddRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
- this.AddRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest);
- this.AddEventHandler(ExitNotification.Type, this.HandleExitNotification);
-
- this.AddEventHandler(DidOpenTextDocumentNotification.Type, this.HandleDidOpenTextDocumentNotification);
- this.AddEventHandler(DidCloseTextDocumentNotification.Type, this.HandleDidCloseTextDocumentNotification);
- this.AddEventHandler(DidChangeTextDocumentNotification.Type, this.HandleDidChangeTextDocumentNotification);
- this.AddEventHandler(DidChangeConfigurationNotification.Type, this.HandleDidChangeConfigurationNotification);
-
- this.AddRequestHandler(DefinitionRequest.Type, this.HandleDefinitionRequest);
- this.AddRequestHandler(ReferencesRequest.Type, this.HandleReferencesRequest);
- this.AddRequestHandler(CompletionRequest.Type, this.HandleCompletionRequest);
- this.AddRequestHandler(CompletionResolveRequest.Type, this.HandleCompletionResolveRequest);
- this.AddRequestHandler(SignatureHelpRequest.Type, this.HandleSignatureHelpRequest);
- this.AddRequestHandler(DocumentHighlightRequest.Type, this.HandleDocumentHighlightRequest);
- this.AddRequestHandler(HoverRequest.Type, this.HandleHoverRequest);
- this.AddRequestHandler(DocumentSymbolRequest.Type, this.HandleDocumentSymbolRequest);
- this.AddRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest);
-
- this.AddRequestHandler(ShowOnlineHelpRequest.Type, this.HandleShowOnlineHelpRequest);
- this.AddRequestHandler(ExpandAliasRequest.Type, this.HandleExpandAliasRequest);
-
- this.AddRequestHandler(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest);
+ this.editorSession = new EditorSession();
+ this.editorSession.StartSession();
+ this.editorSession.PowerShellContext.OutputWritten += this.powerShellContext_OutputWritten;
}
- public void AddRequestHandler(
- RequestType requestType,
- Func, Task> requestHandler)
+ protected override void Initialize()
{
- this.messageDispatcher.AddRequestHandler(
- requestType,
- requestHandler);
- }
+ // Register all supported message types
- public void AddEventHandler(
- EventType eventType,
- Func eventHandler)
- {
- this.messageDispatcher.AddEventHandler(
- eventType,
- eventHandler);
+ this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
+
+ 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(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest);
}
- public async Task ProcessMessage(
- Message messageToProcess,
- EditorSession editorSession,
- MessageWriter messageWriter)
+ protected override void Shutdown()
{
- await this.messageDispatcher.DispatchMessage(
- messageToProcess,
- editorSession,
- messageWriter);
+ Logger.Write(LogLevel.Normal, "Language service is shutting down...");
+
+ this.editorSession.Dispose();
}
#region Built-in Message Handlers
protected async Task HandleInitializeRequest(
InitializeRequest initializeParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
// Grab the workspace path from the parameters
editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
@@ -125,20 +107,9 @@ await requestContext.SendResult(
});
}
- protected Task HandleShutdownRequest(
- object shutdownParams,
- EditorSession editorSession,
- RequestContext requestContext)
- {
- // TODO: Shut down!
-
- return Task.FromResult(true);
- }
-
protected async Task HandleShowOnlineHelpRequest(
string helpParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
if (helpParams == null) { helpParams = "get-help"; }
@@ -155,8 +126,7 @@ await editorSession.PowerShellContext.ExecuteCommand(
private async Task HandleExpandAliasRequest(
string content,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
var script = @"
function __Expand-Alias {
@@ -183,28 +153,17 @@ Sort Start -Descending
}";
var psCommand = new PSCommand();
psCommand.AddScript(script);
- await editorSession.PowerShellContext.ExecuteCommand(psCommand);
+ await this.editorSession.PowerShellContext.ExecuteCommand(psCommand);
psCommand = new PSCommand();
psCommand.AddCommand("__Expand-Alias").AddArgument(content);
- var result = await editorSession.PowerShellContext.ExecuteCommand(psCommand);
+ var result = await this.editorSession.PowerShellContext.ExecuteCommand(psCommand);
await requestContext.SendResult(result.First().ToString());
}
- protected Task HandleExitNotification(
- object exitParams,
- EditorSession editorSession,
- EventContext eventContext)
- {
- // TODO: Shut down!
-
- return Task.FromResult(true);
- }
-
protected Task HandleDidOpenTextDocumentNotification(
DidOpenTextDocumentNotification openParams,
- EditorSession editorSession,
EventContext eventContext)
{
ScriptFile openedFile =
@@ -225,7 +184,6 @@ protected Task HandleDidOpenTextDocumentNotification(
protected Task HandleDidCloseTextDocumentNotification(
TextDocumentIdentifier closeParams,
- EditorSession editorSession,
EventContext eventContext)
{
// Find and close the file in the current session
@@ -243,7 +201,6 @@ protected Task HandleDidCloseTextDocumentNotification(
protected Task HandleDidChangeTextDocumentNotification(
DidChangeTextDocumentParams textChangeParams,
- EditorSession editorSession,
EventContext eventContext)
{
List changedFiles = new List();
@@ -272,7 +229,6 @@ protected Task HandleDidChangeTextDocumentNotification(
protected async Task HandleDidChangeConfigurationNotification(
DidChangeConfigurationParams configChangeParams,
- EditorSession editorSession,
EventContext eventContext)
{
bool oldScriptAnalysisEnabled =
@@ -302,8 +258,7 @@ await PublishScriptDiagnostics(
protected async Task HandleDefinitionRequest(
TextDocumentPosition textDocumentPosition,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -342,8 +297,7 @@ await editorSession.LanguageService.GetDefinitionOfSymbol(
protected async Task HandleReferencesRequest(
ReferencesParams referencesParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -387,8 +341,7 @@ await editorSession.LanguageService.FindReferencesOfSymbol(
protected async Task HandleCompletionRequest(
TextDocumentPosition textDocumentPosition,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
int cursorLine = textDocumentPosition.Position.Line + 1;
int cursorColumn = textDocumentPosition.Position.Character + 1;
@@ -455,8 +408,7 @@ await editorSession.LanguageService.GetCompletionsInFile(
protected async Task HandleCompletionResolveRequest(
CompletionItem completionItem,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
if (completionItem.Kind == CompletionItemKind.Function)
{
@@ -483,8 +435,7 @@ protected async Task HandleCompletionResolveRequest(
protected async Task HandleSignatureHelpRequest(
TextDocumentPosition textDocumentPosition,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -535,8 +486,7 @@ await requestContext.SendResult(
protected async Task HandleDocumentHighlightRequest(
TextDocumentPosition textDocumentPosition,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -575,8 +525,7 @@ protected async Task HandleDocumentHighlightRequest(
protected async Task HandleHoverRequest(
TextDocumentPosition textDocumentPosition,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -625,8 +574,7 @@ await requestContext.SendResult(
protected async Task HandleDocumentSymbolRequest(
TextDocumentIdentifier textDocumentIdentifier,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
ScriptFile scriptFile =
editorSession.Workspace.GetFile(
@@ -699,8 +647,7 @@ private string GetDecoratedSymbolName(SymbolReference symbolReference)
protected async Task HandleWorkspaceSymbolRequest(
WorkspaceSymbolParams workspaceSymbolParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
var symbols = new List();
@@ -748,8 +695,7 @@ private bool IsQueryMatch(string query, string symbolName)
protected async Task HandleEvaluateRequest(
DebugAdapterMessages.EvaluateRequestArguments evaluateParams,
- EditorSession editorSession,
- RequestContext requestContext)
+ RequestContext requestContext)
{
VariableDetails result =
await editorSession.DebugService.EvaluateExpression(
@@ -777,6 +723,21 @@ await requestContext.SendResult(
#endregion
+ #region Event Handlers
+
+ async void powerShellContext_OutputWritten(object sender, OutputWrittenEventArgs e)
+ {
+ await this.SendEvent(
+ DebugAdapterMessages.OutputEvent.Type,
+ new DebugAdapterMessages.OutputEventBody
+ {
+ Output = e.OutputText + (e.IncludeNewLine ? "\r\n" : string.Empty),
+ Category = (e.OutputType == OutputType.Error) ? "stderr" : "stdout"
+ });
+ }
+
+ #endregion
+
#region Helper Methods
private static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion)
diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs
new file mode 100644
index 000000000..d869f1f07
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs
@@ -0,0 +1,82 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
+{
+ public abstract class LanguageServerBase : ProtocolServer
+ {
+ private bool isStarted;
+ private ChannelBase serverChannel;
+ private TaskCompletionSource serverExitedTask;
+
+ public LanguageServerBase(ChannelBase serverChannel) :
+ base(serverChannel, MessageProtocolType.LanguageServer)
+ {
+ this.serverChannel = serverChannel;
+ }
+
+ protected override void OnStart()
+ {
+ // Register handlers for server lifetime messages
+ this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest);
+ this.SetEventHandler(ExitNotification.Type, this.HandleExitNotification);
+
+ // Initialize the implementation class
+ this.Initialize();
+ }
+
+ protected override void OnStop()
+ {
+ this.Shutdown();
+ }
+
+ ///
+ /// 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.
+ }
+
+ private Task HandleShutdownRequest(
+ object shutdownParams,
+ RequestContext requestContext)
+ {
+ // Allow the implementor to shut down gracefully
+ this.Shutdown();
+
+ return requestContext.SendResult(new object());
+ }
+
+ private Task HandleExitNotification(
+ object exitParams,
+ EventContext eventContext)
+ {
+ // Stop the server channel
+ this.Stop();
+
+ // Notify any waiter that the server has exited
+ if (this.serverExitedTask != null)
+ {
+ this.serverExitedTask.SetResult(true);
+ }
+
+ return Task.FromResult(true);
+ }
+ }
+}
+
diff --git a/src/PowerShellEditorServices.Host/LanguageServerSettings.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs
similarity index 87%
rename from src/PowerShellEditorServices.Host/LanguageServerSettings.cs
rename to src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs
index 5d46c9f46..256a81c99 100644
--- a/src/PowerShellEditorServices.Host/LanguageServerSettings.cs
+++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs
@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-namespace Microsoft.PowerShell.EditorServices.Host
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
{
- internal class LanguageServerSettings
+ public class LanguageServerSettings
{
public ScriptAnalysisSettings ScriptAnalysis { get; set; }
@@ -23,7 +23,7 @@ public void Update(LanguageServerSettings settings)
}
}
- internal class ScriptAnalysisSettings
+ public class ScriptAnalysisSettings
{
public bool? Enable { get; set; }
@@ -41,7 +41,7 @@ public void Update(ScriptAnalysisSettings settings)
}
}
- internal class SettingsWrapper
+ public class SettingsWrapper
{
// NOTE: This property is capitalized as 'Powershell' because the
// mode name sent from the client is written as 'powershell' and
diff --git a/src/PowerShellEditorServices.Protocol/Server/ProtocolServer.cs b/src/PowerShellEditorServices.Protocol/Server/ProtocolServer.cs
new file mode 100644
index 000000000..e3292c9f1
--- /dev/null
+++ b/src/PowerShellEditorServices.Protocol/Server/ProtocolServer.cs
@@ -0,0 +1,151 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerShell.EditorServices.Protocol.Server
+{
+ public abstract class ProtocolServer
+ {
+ private bool isStarted;
+ private ChannelBase serverChannel;
+ private MessageProtocolType messageProtocolType;
+ private TaskCompletionSource serverExitedTask;
+ private SynchronizationContext originalSynchronizationContext;
+
+ ///
+ /// Initializes an instance of the protocol server using the
+ /// specified channel for communication.
+ ///
+ /// The channel to use for communication with the client.
+ /// The type of message protocol used by the server.
+ public ProtocolServer(
+ ChannelBase serverChannel,
+ MessageProtocolType messageProtocolType)
+ {
+ this.serverChannel = serverChannel;
+ this.messageProtocolType = messageProtocolType;
+ this.originalSynchronizationContext = SynchronizationContext.Current;
+ }
+
+ public void Start()
+ {
+ if (!this.isStarted)
+ {
+ // Start the provided server channel
+ this.serverChannel.Start(this.messageProtocolType);
+
+ // Listen for unhandled exceptions from the dispatcher
+ this.serverChannel.MessageDispatcher.UnhandledException += MessageDispatcher_UnhandledException;
+
+ // Notify implementation about server start
+ this.OnStart();
+
+ // Server is now started
+ this.isStarted = true;
+ }
+ }
+
+ public void WaitForExit()
+ {
+ this.serverExitedTask = new TaskCompletionSource();
+ this.serverExitedTask.Task.Wait();
+ }
+
+ public void Stop()
+ {
+ if (this.isStarted)
+ {
+ // Stop the implementation first
+ this.OnStop();
+
+ this.serverChannel.Stop();
+ this.serverExitedTask.SetResult(true);
+ this.isStarted = false;
+ }
+ }
+
+ public void SetRequestHandler(
+ RequestType requestType,
+ Func, Task> requestHandler)
+ {
+ this.serverChannel.MessageDispatcher.SetRequestHandler(
+ requestType,
+ requestHandler);
+ }
+
+ public void SetEventHandler(
+ EventType eventType,
+ Func eventHandler)
+ {
+ this.serverChannel.MessageDispatcher.SetEventHandler(
+ eventType,
+ eventHandler);
+ }
+
+ ///
+ /// Sends an event to the channel's endpoint.
+ ///
+ /// The event parameter type.
+ /// The type of event being sent.
+ /// The event parameters being sent.
+ /// A Task that tracks completion of the send operation.
+ public Task SendEvent(
+ EventType eventType,
+ TParams eventParams)
+ {
+ // In a server, some events could be raised from a different
+ // thread. To ensure that messages are written serially,
+ // dispatch the SendEvent call to the message loop thread.
+
+ if (!this.serverChannel.MessageDispatcher.InMessageLoopThread)
+ {
+ this.serverChannel.MessageDispatcher.SynchronizationContext.Post(
+ async (obj) =>
+ {
+ await this.serverChannel.MessageWriter.WriteMessage(
+ Message.Event(
+ eventType.MethodName,
+ JToken.FromObject(eventParams)));
+ }, null);
+
+ return Task.FromResult(true);
+ }
+ else
+ {
+ return this.serverChannel.MessageWriter.WriteMessage(
+ Message.Event(
+ eventType.MethodName,
+ JToken.FromObject(eventParams)));
+ }
+ }
+
+ protected virtual void OnStart()
+ {
+ }
+
+ protected virtual void OnStop()
+ {
+ }
+
+ private void MessageDispatcher_UnhandledException(object sender, Exception e)
+ {
+ if (this.serverExitedTask != null)
+ {
+ this.serverExitedTask.SetException(e);
+ }
+ else if (this.originalSynchronizationContext != null)
+ {
+ this.originalSynchronizationContext.Post(o => { throw e; }, null);
+ }
+ }
+ }
+}
+
diff --git a/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs b/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs
index 27bd4caa0..3bacc0ac5 100644
--- a/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs
+++ b/src/PowerShellEditorServices/Debugging/StackFrameDetails.cs
@@ -47,6 +47,7 @@ public class StackFrameDetails
///
///
/// A variable container with all the local variables for this stack frame.
+ ///
/// A new instance of the StackFrameDetails class.
static internal StackFrameDetails Create(
CallStackFrame callStackFrame,
diff --git a/src/PowerShellEditorServices/IHost.cs b/src/PowerShellEditorServices/IHost.cs
deleted file mode 100644
index ef68a3437..000000000
--- a/src/PowerShellEditorServices/IHost.cs
+++ /dev/null
@@ -1,30 +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;
-
-namespace Microsoft.PowerShell.EditorServices
-{
- ///
- /// Provides an interface for starting and identifying a host.
- ///
- public interface IHost
- {
- ///
- /// Gets the host application's identifying name.
- ///
- string Name { get; }
-
- ///
- /// Gets the host application's version number.
- ///
- Version Version { get; }
-
- ///
- /// Starts the host's message pump.
- ///
- void Start();
- }
-}
diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
index a7707d85d..a8d718113 100644
--- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj
+++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
@@ -66,7 +66,6 @@
-
diff --git a/src/PowerShellEditorServices/Session/EditorSession.cs b/src/PowerShellEditorServices/Session/EditorSession.cs
index e3c452a54..b99a1cb25 100644
--- a/src/PowerShellEditorServices/Session/EditorSession.cs
+++ b/src/PowerShellEditorServices/Session/EditorSession.cs
@@ -50,11 +50,7 @@ public class EditorSession
/// Starts the session using the provided IConsoleHost implementation
/// for the ConsoleService.
///
- ///
- /// An IConsoleHost implementation which is used to interact with the
- /// host's user interface.
- ///
- public void StartSession(IConsoleHost consoleHost)
+ public void StartSession()
{
// Create a workspace to contain open files
this.Workspace = new Workspace();
diff --git a/src/PowerShellEditorServices/Session/PowerShellContext.cs b/src/PowerShellEditorServices/Session/PowerShellContext.cs
index 4ef1f4e56..3fbde817f 100644
--- a/src/PowerShellEditorServices/Session/PowerShellContext.cs
+++ b/src/PowerShellEditorServices/Session/PowerShellContext.cs
@@ -341,10 +341,24 @@ public async Task ExecuteScriptAtPath(string scriptPath)
///
public void AbortExecution()
{
- Logger.Write(LogLevel.Verbose, "Execution abort requested...");
+ if (this.SessionState != PowerShellContextState.Aborting)
+ {
+ Logger.Write(LogLevel.Verbose, "Execution abort requested...");
+
+ this.powerShell.BeginStop(null, null);
+ this.SessionState = PowerShellContextState.Aborting;
- this.powerShell.BeginStop(null, null);
- this.ResumeDebugger(DebuggerResumeAction.Stop);
+ if (this.IsDebuggerStopped)
+ {
+ this.ResumeDebugger(DebuggerResumeAction.Stop);
+ }
+ }
+ else
+ {
+ Logger.Write(
+ LogLevel.Verbose,
+ "Execution abort requested while already aborting");
+ }
}
///
@@ -379,6 +393,13 @@ internal void ResumeDebugger(DebuggerResumeAction resumeAction)
///
public void Dispose()
{
+ // Do we need to abort a running execution?
+ if (this.SessionState == PowerShellContextState.Running ||
+ this.IsDebuggerStopped)
+ {
+ this.AbortExecution();
+ }
+
this.SessionState = PowerShellContextState.Disposed;
if (this.powerShell != null)
@@ -616,7 +637,12 @@ private void OnDebuggerStop(object sender, DebuggerStopEventArgs e)
this.pipelineExecutionTask = new TaskCompletionSource();
// Update the session state
- this.OnSessionStateChanged(this, new SessionStateChangedEventArgs(PowerShellContextState.Ready, PowerShellExecutionResult.Stopped, null));
+ this.OnSessionStateChanged(
+ this,
+ new SessionStateChangedEventArgs(
+ PowerShellContextState.Ready,
+ PowerShellExecutionResult.Stopped,
+ null));
// Raise the event for the debugger service
if (this.DebuggerStop != null)
diff --git a/src/PowerShellEditorServices/Utility/Logger.cs b/src/PowerShellEditorServices/Utility/Logger.cs
index b484cc452..512fca562 100644
--- a/src/PowerShellEditorServices/Utility/Logger.cs
+++ b/src/PowerShellEditorServices/Utility/Logger.cs
@@ -185,6 +185,11 @@ private bool TryOpenLogFile(
{
try
{
+ // Make sure the log directory exists
+ Directory.CreateDirectory(
+ Path.GetDirectoryName(
+ logFilePath));
+
// Open the log file for writing with UTF8 encoding
this.textWriter =
new StreamWriter(
diff --git a/test/PowerShellEditorServices.Test.Host/AttachHelper.cs b/test/PowerShellEditorServices.Test.Host/AttachHelper.cs
new file mode 100644
index 000000000..214aa2dba
--- /dev/null
+++ b/test/PowerShellEditorServices.Test.Host/AttachHelper.cs
@@ -0,0 +1,111 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using EnvDTE;
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.PowerShell.EditorServices.Test.Host
+{
+ internal class AttachHelper
+ {
+ public static void AttachToProcessIfDebugging(int processId)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ int tryCount = 5;
+
+ while (tryCount-- > 0)
+ {
+ try
+ {
+ var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0");
+ var processes = dte.Debugger.LocalProcesses.OfType();
+ var foundProcess = processes.SingleOrDefault(x => x.ProcessID == processId);
+
+ //EnvDTE.Process foundProcess = null;
+ //for (int i = 0; i < dte.Debugger.LocalProcesses.Count; i++)
+ //{
+ // foundProcess = dte.Debugger.LocalProcesses.Item(i) as EnvDTE.Process;
+
+ // if (foundProcess != null && foundProcess.ProcessID == processId)
+ // {
+ // break;
+ // }
+ //}
+
+ if (foundProcess != null)
+ {
+ foundProcess.Attach();
+ break;
+ }
+ else
+ {
+ throw new InvalidOperationException("Could not find language service process!");
+ }
+ }
+ catch (COMException)
+ {
+ // Wait a bit and try again
+ System.Threading.Thread.Sleep(1000);
+ }
+ }
+ }
+ }
+ }
+
+ [ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IOleMessageFilter
+ {
+ [PreserveSig]
+ int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
+
+ [PreserveSig]
+ int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
+
+ [PreserveSig]
+ int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
+ }
+
+ public class MessageFilter : IOleMessageFilter
+ {
+ private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;
+
+ int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
+ {
+ return Handled;
+ }
+
+ int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
+ {
+ return dwRejectType == RetryAllowed ? Retry : Cancel;
+ }
+
+ int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
+ {
+ return WaitAndDispatch;
+ }
+
+ public static void Register()
+ {
+ CoRegisterMessageFilter(new MessageFilter());
+ }
+
+ public static void Revoke()
+ {
+ CoRegisterMessageFilter(null);
+ }
+
+ private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
+ {
+ IOleMessageFilter oldFilter;
+ CoRegisterMessageFilter(newFilter, out oldFilter);
+ }
+
+ [DllImport("Ole32.dll")]
+ private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
+ }
+}
diff --git a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs
new file mode 100644
index 000000000..f42159f9d
--- /dev/null
+++ b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs
@@ -0,0 +1,125 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.PowerShell.EditorServices.Protocol.Client;
+using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Microsoft.PowerShell.EditorServices.Test.Host
+{
+ public class DebugAdapterTests : IAsyncLifetime
+ {
+ private DebugAdapterClient debugAdapterClient;
+ private string DebugScriptPath =
+ Path.GetFullPath(@"..\..\..\PowerShellEditorServices.Test.Shared\Debugging\DebugTest.ps1");
+
+ public Task InitializeAsync()
+ {
+ string testLogPath =
+ Path.Combine(
+ AppDomain.CurrentDomain.BaseDirectory,
+ "logs",
+ this.GetType().Name,
+ Guid.NewGuid().ToString().Substring(0, 8) + ".log");
+
+ Console.WriteLine(" Output log at path: {0}", testLogPath);
+
+ this.debugAdapterClient =
+ new DebugAdapterClient(
+ new StdioClientChannel(
+ "Microsoft.PowerShell.EditorServices.Host.exe",
+ "/debugAdapter",
+ "/logPath:\"" + testLogPath + "\""));
+
+ return this.debugAdapterClient.Start();
+ }
+
+ public Task DisposeAsync()
+ {
+ return this.debugAdapterClient.Stop();
+ }
+
+ [Fact]
+ public async Task DebugAdapterStopsOnBreakpoints()
+ {
+ await this.SendRequest(
+ SetBreakpointsRequest.Type,
+ new SetBreakpointsRequestArguments
+ {
+ Source = new Source
+ {
+ Path = DebugScriptPath
+ },
+ Lines = new int[] { 5, 9 }
+ });
+
+ Task breakEventTask = this.WaitForEvent(StoppedEvent.Type);
+ await this.LaunchScript(DebugScriptPath);
+
+ // Wait for a couple breakpoints
+ StoppedEventBody stoppedDetails = await breakEventTask;
+ Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
+ Assert.Equal(5, stoppedDetails.Line);
+
+ breakEventTask = this.WaitForEvent(StoppedEvent.Type);
+ await this.SendRequest(ContinueRequest.Type, new object());
+ stoppedDetails = await breakEventTask;
+ Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path);
+ Assert.Equal(9, stoppedDetails.Line);
+
+ // Abort script execution
+ Task terminatedEvent = this.WaitForEvent(TerminatedEvent.Type);
+ await this.SendRequest(DisconnectRequest.Type, new object());
+ await terminatedEvent;
+ }
+
+ private Task LaunchScript(string scriptPath)
+ {
+ return this.debugAdapterClient.LaunchScript(scriptPath);
+ }
+
+ private Task SendRequest(
+ RequestType requestType,
+ TParams requestParams)
+ {
+ return
+ this.debugAdapterClient.SendRequest(
+ requestType,
+ requestParams);
+ }
+
+ private Task SendEvent(EventType eventType, TParams eventParams)
+ {
+ return
+ this.debugAdapterClient.SendEvent(
+ eventType,
+ eventParams);
+ }
+
+ private Task WaitForEvent(EventType eventType)
+ {
+ TaskCompletionSource eventTask = new TaskCompletionSource();
+
+ this.debugAdapterClient.SetEventHandler(
+ eventType,
+ (p, ctx) =>
+ {
+ eventTask.SetResult(p);
+ return Task.FromResult(true);
+ },
+ true); // Override any existing handler
+
+ return eventTask.Task;
+ }
+ }
+}
+
diff --git a/test/PowerShellEditorServices.Test.Host/ScenarioTests.cs b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs
similarity index 83%
rename from test/PowerShellEditorServices.Test.Host/ScenarioTests.cs
rename to test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs
index c37720443..12a92d38e 100644
--- a/test/PowerShellEditorServices.Test.Host/ScenarioTests.cs
+++ b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs
@@ -3,44 +3,47 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using Microsoft.PowerShell.EditorServices.Protocol.Client;
using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
-using Newtonsoft.Json.Linq;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
namespace Microsoft.PowerShell.EditorServices.Test.Host
{
- public class ScenarioTests : IDisposable
+ public class LanguageServerTests : IAsyncLifetime
{
- private int messageId = 0;
+ private LanguageServiceClient languageServiceClient;
- private LanguageServiceManager languageServiceManager =
- new LanguageServiceManager();
-
- private MessageReader MessageReader
- {
- get { return this.languageServiceManager.MessageReader; }
- }
-
- private MessageWriter MessageWriter
+ public Task InitializeAsync()
{
- get { return this.languageServiceManager.MessageWriter; }
+ string testLogPath =
+ Path.Combine(
+ AppDomain.CurrentDomain.BaseDirectory,
+ "logs",
+ this.GetType().Name,
+ Guid.NewGuid().ToString().Substring(0, 8) + ".log");
+
+ Console.WriteLine(" Output log at path: {0}", testLogPath);
+
+ this.languageServiceClient =
+ new LanguageServiceClient(
+ new StdioClientChannel(
+ "Microsoft.PowerShell.EditorServices.Host.exe",
+ "/logPath:\"" + testLogPath + "\""));
+
+ return this.languageServiceClient.Start();
}
- public ScenarioTests()
+ public Task DisposeAsync()
{
- this.languageServiceManager.Start();
- }
-
- public void Dispose()
- {
- this.languageServiceManager.Stop();
+ return this.languageServiceClient.Stop();
}
[Fact]
@@ -50,7 +53,9 @@ public async Task ServiceReturnsSyntaxErrors()
await this.SendOpenFileEvent("TestFiles\\SimpleSyntaxError.ps1", false);
// Wait for the diagnostic event
- PublishDiagnosticsNotification diagnostics = this.WaitForEvent(PublishDiagnosticsNotification.Type);
+ PublishDiagnosticsNotification diagnostics =
+ await this.WaitForEvent(
+ PublishDiagnosticsNotification.Type);
// Was there a syntax error?
Assert.NotEqual(0, diagnostics.Diagnostics.Length);
@@ -415,16 +420,22 @@ await this.SendRequest(
[Fact]
public async Task ServiceExecutesReplCommandAndReceivesOutput()
{
- await this.SendRequestWithoutWait(
- EvaluateRequest.Type,
- new EvaluateRequestArguments
- {
- Expression = "1 + 2"
- });
+ Task outputEventTask =
+ this.WaitForEvent(
+ OutputEvent.Type);
+
+ Task evaluateTask =
+ this.SendRequest(
+ EvaluateRequest.Type,
+ new EvaluateRequestArguments
+ {
+ Expression = "1 + 2"
+ });
- OutputEventBody outputEvent = this.WaitForEvent(OutputEvent.Type);
- this.WaitForResponse(EvaluateRequest.Type, this.messageId);
+ // Wait for both the evaluate response and the output event
+ await Task.WhenAll(evaluateTask, outputEventTask);
+ OutputEventBody outputEvent = outputEventTask.Result;
Assert.Equal("3\r\n", outputEvent.Output);
Assert.Equal("stdout", outputEvent.Category);
}
@@ -483,39 +494,39 @@ public async Task ServiceExecutesReplCommandAndReceivesChoicePrompt()
// Assert.Equal("0", replWriteLineEvent.Body.LineContents);
}
- private async Task SendRequest(
- RequestType requestType,
+ private Task SendRequest(
+ RequestType requestType,
TParams requestParams)
{
- await this.SendRequestWithoutWait(requestType, requestParams);
- return this.WaitForResponse(requestType, this.messageId);
+ return
+ this.languageServiceClient.SendRequest(
+ requestType,
+ requestParams);
}
- private async Task SendRequestWithoutWait(
- RequestType requestType,
- TParams requestParams)
+ private Task SendEvent(EventType eventType, TParams eventParams)
{
- this.messageId++;
-
- await this.MessageWriter.WriteMessage(
- Message.Request(
- this.messageId.ToString(),
- requestType.TypeName,
- JToken.FromObject(requestParams)));
- }
-
- private async Task SendEvent(EventType eventType, TParams eventParams)
- {
- await this.MessageWriter.WriteMessage(
- Message.Event(
- eventType.MethodName,
- JToken.FromObject(eventParams)));
+ return
+ this.languageServiceClient.SendEvent(
+ eventType,
+ eventParams);
}
private async Task SendOpenFileEvent(string filePath, bool waitForDiagnostics = true)
{
string fileContents = string.Join(Environment.NewLine, File.ReadAllLines(filePath));
+ // Start the event waiter for diagnostics before sending the
+ // open event to make sure that we catch it
+ Task diagnosticWaitTask = null;
+ if (waitForDiagnostics)
+ {
+ // Wait for the diagnostic event
+ diagnosticWaitTask =
+ this.WaitForEvent(
+ PublishDiagnosticsNotification.Type);
+ }
+
await this.SendEvent(
DidOpenTextDocumentNotification.Type,
new DidOpenTextDocumentNotification()
@@ -524,41 +535,26 @@ await this.SendEvent(
Text = fileContents
});
- if (waitForDiagnostics)
+ if (diagnosticWaitTask != null)
{
- // Wait for the diagnostic event
- this.WaitForEvent(PublishDiagnosticsNotification.Type);
+ await diagnosticWaitTask;
}
}
- private TParams WaitForEvent(EventType eventType)
+ private Task WaitForEvent(EventType eventType)
{
- // TODO: Integrate timeout!
- Message receivedMessage = this.MessageReader.ReadMessage().Result;
-
- Assert.Equal(MessageType.Event, receivedMessage.MessageType);
- Assert.Equal(eventType.MethodName, receivedMessage.Method);
-
- return
- receivedMessage.Contents != null ?
- receivedMessage.Contents.ToObject() :
- default(TParams);
- }
+ TaskCompletionSource eventTask = new TaskCompletionSource();
- private TResult WaitForResponse(
- RequestType requestType,
- int expectedId)
- {
- // TODO: Integrate timeout!
- Message receivedMessage = this.MessageReader.ReadMessage().Result;
-
- Assert.Equal(MessageType.Response, receivedMessage.MessageType);
- Assert.Equal(expectedId.ToString(), receivedMessage.Id);
+ this.languageServiceClient.SetEventHandler(
+ eventType,
+ (p, ctx) =>
+ {
+ eventTask.SetResult(p);
+ return Task.FromResult(true);
+ },
+ true); // Override any existing handler
- return
- receivedMessage.Contents != null ?
- receivedMessage.Contents.ToObject() :
- default(TResult);
+ return eventTask.Task;
}
}
}
diff --git a/test/PowerShellEditorServices.Test.Host/LanguageServiceManager.cs b/test/PowerShellEditorServices.Test.Host/LanguageServiceManager.cs
deleted file mode 100644
index cebba8102..000000000
--- a/test/PowerShellEditorServices.Test.Host/LanguageServiceManager.cs
+++ /dev/null
@@ -1,220 +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 EnvDTE;
-using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
-using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Xunit;
-
-namespace Microsoft.PowerShell.EditorServices.Test.Host
-{
- public class LanguageServiceManager
- {
- Stream inputStream;
- Stream outputStream;
- System.Diagnostics.Process languageServiceProcess;
-
- public MessageReader MessageReader { get; private set; }
-
- public MessageWriter MessageWriter { get; private set; }
-
- public void Start()
- {
- // If the test is running in the debugger, tell the language
- // service to also wait for the debugger
- string languageServiceArguments = string.Empty;
- if (System.Diagnostics.Debugger.IsAttached)
- {
- languageServiceArguments = "/waitForDebugger";
- }
-
- this.languageServiceProcess = new System.Diagnostics.Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = "Microsoft.PowerShell.EditorServices.Host.exe",
- Arguments = languageServiceArguments,
- CreateNoWindow = true,
- UseShellExecute = false,
- RedirectStandardInput = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- StandardOutputEncoding = Encoding.UTF8,
- },
- EnableRaisingEvents = true,
- };
-
- // Start the process
- this.languageServiceProcess.Start();
-
- // Attach to the language service process if debugging
- if (System.Diagnostics.Debugger.IsAttached)
- {
- AttachToProcessIfDebugging(this.languageServiceProcess.Id);
- }
-
- IMessageSerializer messageSerializer = new JsonRpcMessageSerializer();
-
- // Open the standard input/output streams
- this.inputStream = this.languageServiceProcess.StandardOutput.BaseStream;
- this.outputStream = this.languageServiceProcess.StandardInput.BaseStream;
-
- // Set up the message reader and writer
- this.MessageReader =
- new MessageReader(
- this.inputStream,
- messageSerializer);
- this.MessageWriter =
- new MessageWriter(
- this.outputStream,
- messageSerializer);
-
-
- // Send the 'initialize' request and wait for the response
- var initializeRequest = new InitializeRequest
- {
- RootPath = "",
- Capabilities = new ClientCapabilities()
- };
-
- // TODO: Assert some capability data?
- this.MessageWriter.WriteRequest(InitializeRequest.Type, initializeRequest, 1).Wait();
- Message initializeResponse = this.MessageReader.ReadMessage().Result;
- }
-
- public void Stop()
- {
- if (this.inputStream != null)
- {
- this.inputStream.Dispose();
- this.inputStream = null;
- }
-
- if (this.outputStream != null)
- {
- this.outputStream.Dispose();
- this.outputStream = null;
- }
-
- if (this.MessageReader != null)
- {
- this.MessageReader = null;
- }
-
- if (this.MessageWriter != null)
- {
- this.MessageWriter = null;
- }
-
- if (this.languageServiceProcess != null)
- {
- this.languageServiceProcess.Kill();
- this.languageServiceProcess = null;
- }
- }
-
- private static void AttachToProcessIfDebugging(int processId)
- {
- if (System.Diagnostics.Debugger.IsAttached)
- {
- int tryCount = 5;
-
- while (tryCount-- > 0)
- {
- try
- {
- var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0");
- var processes = dte.Debugger.LocalProcesses.OfType();
- var foundProcess = processes.SingleOrDefault(x => x.ProcessID == processId);
-
- //EnvDTE.Process foundProcess = null;
- //for (int i = 0; i < dte.Debugger.LocalProcesses.Count; i++)
- //{
- // foundProcess = dte.Debugger.LocalProcesses.Item(i) as EnvDTE.Process;
-
- // if (foundProcess != null && foundProcess.ProcessID == processId)
- // {
- // break;
- // }
- //}
-
- if (foundProcess != null)
- {
- foundProcess.Attach();
- break;
- }
- else
- {
- throw new InvalidOperationException("Could not find language service process!");
- }
- }
- catch (COMException)
- {
- // Wait a bit and try again
- System.Threading.Thread.Sleep(1000);
- }
- }
- }
- }
- }
-
- [ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IOleMessageFilter
- {
- [PreserveSig]
- int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
-
- [PreserveSig]
- int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
-
- [PreserveSig]
- int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
- }
-
- public class MessageFilter : IOleMessageFilter
- {
- private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;
-
- int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
- {
- return Handled;
- }
-
- int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
- {
- return dwRejectType == RetryAllowed ? Retry : Cancel;
- }
-
- int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
- {
- return WaitAndDispatch;
- }
-
- public static void Register()
- {
- CoRegisterMessageFilter(new MessageFilter());
- }
-
- public static void Revoke()
- {
- CoRegisterMessageFilter(null);
- }
-
- private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
- {
- IOleMessageFilter oldFilter;
- CoRegisterMessageFilter(newFilter, out oldFilter);
- }
-
- [DllImport("Ole32.dll")]
- private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
- }
-}
diff --git a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj
index bf6f98206..b6e74bba5 100644
--- a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj
+++ b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj
@@ -64,9 +64,10 @@
-
+
+
-
+
diff --git a/test/PowerShellEditorServices.Test.Host/Properties/AssemblyInfo.cs b/test/PowerShellEditorServices.Test.Host/Properties/AssemblyInfo.cs
index b8c4f3f55..2cd2d0726 100644
--- a/test/PowerShellEditorServices.Test.Host/Properties/AssemblyInfo.cs
+++ b/test/PowerShellEditorServices.Test.Host/Properties/AssemblyInfo.cs
@@ -1,4 +1,9 @@
-using System.Reflection;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,7 +15,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PowerShellEditorServices.Test.Host")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyCopyright("Copyright � 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -34,3 +39,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+
diff --git a/test/PowerShellEditorServices.Test.Protocol/DebugAdapter/V8MessageSerializerTests.cs b/test/PowerShellEditorServices.Test.Protocol/DebugAdapter/V8MessageSerializerTests.cs
index 52a7007dd..7dfd47c20 100644
--- a/test/PowerShellEditorServices.Test.Protocol/DebugAdapter/V8MessageSerializerTests.cs
+++ b/test/PowerShellEditorServices.Test.Protocol/DebugAdapter/V8MessageSerializerTests.cs
@@ -1,11 +1,11 @@
-using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Xunit;
namespace Microsoft.PowerShell.EditorServices.Test.Protocol.DebugAdapter
@@ -151,3 +151,4 @@ private static void AssertMessageFields(
}
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Protocol/LanguageServer/JsonRpcMessageSerializerTests.cs b/test/PowerShellEditorServices.Test.Protocol/LanguageServer/JsonRpcMessageSerializerTests.cs
index 59bd137a1..876ca87a3 100644
--- a/test/PowerShellEditorServices.Test.Protocol/LanguageServer/JsonRpcMessageSerializerTests.cs
+++ b/test/PowerShellEditorServices.Test.Protocol/LanguageServer/JsonRpcMessageSerializerTests.cs
@@ -1,11 +1,11 @@
-using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Xunit;
namespace Microsoft.PowerShell.EditorServices.Test.Protocol.LanguageServer
@@ -141,3 +141,4 @@ private static void AssertMessageFields(
}
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs b/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs
index 42d17f56d..a82df2991 100644
--- a/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs
+++ b/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
+using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
using System;
using System.IO;
using System.Text;
@@ -22,7 +23,6 @@ public class MessageReaderWriterTests
public MessageReaderWriterTests()
{
- // TODO: Set this!
this.messageSerializer = new V8MessageSerializer();
}
@@ -174,3 +174,4 @@ private byte[] GetMessageBytes(string messageString, Encoding encoding = null)
}
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Protocol/Properties/AssemblyInfo.cs b/test/PowerShellEditorServices.Test.Protocol/Properties/AssemblyInfo.cs
index 20ebcee88..1a17daf66 100644
--- a/test/PowerShellEditorServices.Test.Protocol/Properties/AssemblyInfo.cs
+++ b/test/PowerShellEditorServices.Test.Protocol/Properties/AssemblyInfo.cs
@@ -1,4 +1,9 @@
-using System.Reflection;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,7 +15,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PowerShellEditorServices.Test.Transport.Stdio")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyCopyright("Copyright � 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -34,3 +39,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandFromModule.cs b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandFromModule.cs
index 2bc5d0461..3177dcbd5 100644
--- a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandFromModule.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandFromModule.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
diff --git a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandInFile.cs b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandInFile.cs
index ff5391cd1..3c201cd9d 100644
--- a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandInFile.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteCommandInFile.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -23,3 +24,4 @@ public class CompleteCommandInFile
"Get-Something");
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteVariableInFile.cs b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteVariableInFile.cs
index fdae6d885..9a728fa69 100644
--- a/test/PowerShellEditorServices.Test.Shared/Completion/CompleteVariableInFile.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Completion/CompleteVariableInFile.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -23,3 +24,4 @@ public class CompleteVariableInFile
"testVar1");
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1 b/test/PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1
index 47d7a8b38..f4c58cc2f 100644
--- a/test/PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1
+++ b/test/PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1
@@ -1,5 +1,4 @@
-Boo-Bah -Doo
-Get-Process -bla
+Get-Process -bla
$i = 1
diff --git a/test/PowerShellEditorServices.Test.Shared/Definition/FindsVariableDefinition.cs b/test/PowerShellEditorServices.Test.Shared/Definition/FindsVariableDefinition.cs
index 246f7b1f0..6dab3ddad 100644
--- a/test/PowerShellEditorServices.Test.Shared/Definition/FindsVariableDefinition.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Definition/FindsVariableDefinition.cs
@@ -1,4 +1,9 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -17,3 +22,4 @@ public class FindsVariableDefinition
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Occurrences/FindOccurrencesOnParameter.cs b/test/PowerShellEditorServices.Test.Shared/Occurrences/FindOccurrencesOnParameter.cs
index 60cc6d6e6..62fc82716 100644
--- a/test/PowerShellEditorServices.Test.Shared/Occurrences/FindOccurrencesOnParameter.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Occurrences/FindOccurrencesOnParameter.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -15,3 +16,4 @@ public class FindOccurrencesOnParameter
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Occurrences/FindsOccurrencesOnFunction.cs b/test/PowerShellEditorServices.Test.Shared/Occurrences/FindsOccurrencesOnFunction.cs
index e5fb59e56..2b8258410 100644
--- a/test/PowerShellEditorServices.Test.Shared/Occurrences/FindsOccurrencesOnFunction.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Occurrences/FindsOccurrencesOnFunction.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -17,3 +18,4 @@ public class FindsOccurrencesOnFunction
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommand.cs b/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommand.cs
index ecff25227..fcb4e88f0 100644
--- a/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommand.cs
+++ b/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommand.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -16,4 +17,4 @@ public class FindsParameterSetsOnCommand
StartColumnNumber = 14
};
}
-}
\ No newline at end of file
+}
diff --git a/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommandWithSpaces.cs b/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommandWithSpaces.cs
index 909e7669e..920530ec3 100644
--- a/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommandWithSpaces.cs
+++ b/test/PowerShellEditorServices.Test.Shared/ParameterHints/FindsParameterSetsOnCommandWithSpaces.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -15,3 +16,4 @@ public class FindsParameterSetsOnCommandWithSpaces
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Properties/AssemblyInfo.cs b/test/PowerShellEditorServices.Test.Shared/Properties/AssemblyInfo.cs
index e70561cf8..164db4ac3 100644
--- a/test/PowerShellEditorServices.Test.Shared/Properties/AssemblyInfo.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Properties/AssemblyInfo.cs
@@ -1,4 +1,9 @@
-using System.Reflection;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,7 +15,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PowerShellEditorServices.Test.Shared")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyCopyright("Copyright � 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -34,3 +39,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+
diff --git a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs
index 2c1789b00..2a22b13f2 100644
--- a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs
+++ b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -25,3 +26,4 @@ public class FindsReferencesOnBuiltInAlias
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunction.cs b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunction.cs
index 633423b60..6a53d69f2 100644
--- a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunction.cs
+++ b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunction.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -15,3 +16,4 @@ public class FindsReferencesOnFunction
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunctionMultiFileDotSource.cs b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunctionMultiFileDotSource.cs
index 4eb4adc5d..5624edf02 100644
--- a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunctionMultiFileDotSource.cs
+++ b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnFunctionMultiFileDotSource.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -27,3 +28,4 @@ public class FindsReferencesOnFunctionMultiFileDotSourceFileC
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesonVariable.cs b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesonVariable.cs
index 6b9b8ce0a..b5ae61af4 100644
--- a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesonVariable.cs
+++ b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesonVariable.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -17,3 +18,4 @@ public class FindsReferencesOnVariable
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInMultiSymbolFile.cs b/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInMultiSymbolFile.cs
index d3904f1fe..7f3dc68e8 100644
--- a/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInMultiSymbolFile.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInMultiSymbolFile.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -12,3 +13,4 @@ public class FindSymbolsInMultiSymbolFile
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInNoSymbolsFile.cs b/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInNoSymbolsFile.cs
index 638894999..cf1692030 100644
--- a/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInNoSymbolsFile.cs
+++ b/test/PowerShellEditorServices.Test.Shared/Symbols/FindSymbolsInNoSymbolsFile.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+//
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
@@ -12,3 +13,4 @@ public class FindSymbolsInNoSymbolsFile
};
}
}
+
diff --git a/test/PowerShellEditorServices.Test/Console/PowerShellContextTests.cs b/test/PowerShellEditorServices.Test/Console/PowerShellContextTests.cs
index b193131f2..3b508332e 100644
--- a/test/PowerShellEditorServices.Test/Console/PowerShellContextTests.cs
+++ b/test/PowerShellEditorServices.Test/Console/PowerShellContextTests.cs
@@ -1,4 +1,9 @@
-using Nito.AsyncEx;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Nito.AsyncEx;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -223,3 +228,4 @@ void OnOutputWritten(object sender, OutputWrittenEventArgs e)
#endregion
}
}
+
diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
index 73a1bfb76..11cc006b2 100644
--- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
@@ -1,9 +1,16 @@
-using Nito.AsyncEx;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Nito.AsyncEx;
using System;
using System.Linq;
using System.Management.Automation;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Sdk;
namespace Microsoft.PowerShell.EditorServices.Test.Debugging
{
@@ -13,6 +20,7 @@ public class DebugServiceTests : IDisposable
private DebugService debugService;
private ScriptFile debugScriptFile;
private PowerShellContext powerShellContext;
+ private SynchronizationContext runnerContext;
private AsyncProducerConsumerQueue debuggerStoppedQueue =
new AsyncProducerConsumerQueue();
@@ -34,6 +42,7 @@ public DebugServiceTests()
this.debugService = new DebugService(this.powerShellContext);
this.debugService.DebuggerStopped += debugService_DebuggerStopped;
this.debugService.BreakpointUpdated += debugService_BreakpointUpdated;
+ this.runnerContext = SynchronizationContext.Current;
}
void powerShellContext_SessionStateChanged(object sender, SessionStateChangedEventArgs e)
@@ -52,7 +61,11 @@ void debugService_BreakpointUpdated(object sender, BreakpointUpdatedEventArgs e)
void debugService_DebuggerStopped(object sender, DebuggerStopEventArgs e)
{
- this.debuggerStoppedQueue.Enqueue(e);
+ this.runnerContext.Post(
+ (o) =>
+ {
+ this.debuggerStoppedQueue.Enqueue(e);
+ }, null);
}
public void Dispose()
@@ -97,32 +110,34 @@ await this.debugService.SetBreakpoints(
new int[] { 5, 9 });
await this.AssertStateChange(PowerShellContextState.Ready);
- this.powerShellContext.ExecuteScriptAtPath(
- this.debugScriptFile.FilePath);
+ Task executeTask =
+ this.powerShellContext.ExecuteScriptAtPath(
+ this.debugScriptFile.FilePath);
// Wait for a couple breakpoints
await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 5);
this.debugService.Continue();
+
await this.AssertDebuggerStopped(this.debugScriptFile.FilePath, 9);
this.debugService.Continue();
// Abort script execution early and wait for completion
this.debugService.Abort();
- await this.AssertStateChange(
- PowerShellContextState.Ready,
- PowerShellExecutionResult.Aborted);
+ await executeTask;
}
[Fact]
public async Task DebuggerBreaksWhenRequested()
{
- this.powerShellContext.ExecuteScriptString(
- this.debugScriptFile.FilePath);
+ Task executeTask =
+ this.powerShellContext.ExecuteScriptString(
+ this.debugScriptFile.FilePath);
// Break execution and wait for the debugger to stop
this.debugService.Break();
- await this.AssertDebuggerStopped(
- this.debugScriptFile.FilePath);
+
+ // File path is an empty string when paused while running
+ await this.AssertDebuggerStopped(string.Empty);
await this.AssertStateChange(
PowerShellContextState.Ready,
PowerShellExecutionResult.Stopped);
@@ -137,8 +152,9 @@ await this.AssertStateChange(
[Fact]
public async Task DebuggerRunsCommandsWhileStopped()
{
- this.powerShellContext.ExecuteScriptString(
- this.debugScriptFile.FilePath);
+ Task executeTask =
+ this.powerShellContext.ExecuteScriptString(
+ this.debugScriptFile.FilePath);
// Break execution and wait for the debugger to stop
this.debugService.Break();
@@ -168,7 +184,10 @@ await this.debugService.SetBreakpoints(
new int[] { 14 });
// Execute the script and wait for the breakpoint to be hit
- this.powerShellContext.ExecuteScriptString(variablesFile.FilePath);
+ Task executeTask =
+ this.powerShellContext.ExecuteScriptString(
+ variablesFile.FilePath);
+
await this.AssertDebuggerStopped(variablesFile.FilePath);
StackFrameDetails[] stackFrames = debugService.GetStackFrames();
@@ -211,15 +230,15 @@ public async Task AssertDebuggerStopped(
string scriptPath,
int lineNumber = -1)
{
+ SynchronizationContext syncContext = SynchronizationContext.Current;
+
DebuggerStopEventArgs eventArgs =
await this.debuggerStoppedQueue.DequeueAsync();
- // TODO #22 - Need to re-enable these Asserts once we figure
- // out how to make them work correctly
- //Assert.Equal(scriptPath, eventArgs.InvocationInfo.ScriptName);
+ Assert.Equal(scriptPath, eventArgs.InvocationInfo.ScriptName);
if (lineNumber > -1)
{
- //Assert.Equal(lineNumber, eventArgs.InvocationInfo.ScriptLineNumber);
+ Assert.Equal(lineNumber, eventArgs.InvocationInfo.ScriptLineNumber);
}
}
@@ -230,9 +249,10 @@ private async Task AssertStateChange(
SessionStateChangedEventArgs newState =
await this.sessionStateQueue.DequeueAsync();
- // TODO #22
- //Assert.Equal(expectedState, newState.NewSessionState);
- //Assert.Equal(expectedResult, newState.ExecutionResult);
+ Assert.Equal(expectedState, newState.NewSessionState);
+ Assert.Equal(expectedResult, newState.ExecutionResult);
}
}
}
+
+
diff --git a/test/PowerShellEditorServices.Test/Properties/AssemblyInfo.cs b/test/PowerShellEditorServices.Test/Properties/AssemblyInfo.cs
index a7deee989..f14268215 100644
--- a/test/PowerShellEditorServices.Test/Properties/AssemblyInfo.cs
+++ b/test/PowerShellEditorServices.Test/Properties/AssemblyInfo.cs
@@ -1,4 +1,9 @@
-using System.Reflection;
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,7 +15,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PowerShellEditorServices.Test.Core")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyCopyright("Copyright � 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -34,3 +39,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+