diff --git a/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs b/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs index 3cb5635b5..5647f1a59 100644 --- a/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs @@ -93,7 +93,7 @@ internal EditorScriptFile( ScriptFile scriptFile) { _scriptFile = scriptFile; - Uri = new Uri(scriptFile.DocumentUri); + Uri = scriptFile.DocumentUri.ToUri(); Lines = _scriptFile.FileLines.AsReadOnly(); } diff --git a/src/PowerShellEditorServices/Extensions/FileContext.cs b/src/PowerShellEditorServices/Extensions/FileContext.cs index 1276726ea..1b563f148 100644 --- a/src/PowerShellEditorServices/Extensions/FileContext.cs +++ b/src/PowerShellEditorServices/Extensions/FileContext.cs @@ -50,7 +50,7 @@ public sealed class FileContext /// /// Gets the URI of the file. /// - public Uri Uri { get; } + public Uri Uri { get; } /// /// Gets the parsed token list for the file. @@ -96,7 +96,7 @@ internal FileContext( this.editorContext = editorContext; this.editorOperations = editorOperations; this.Language = language; - this.Uri = new Uri(scriptFile.DocumentUri); + this.Uri = scriptFile.DocumentUri.ToUri(); } #endregion @@ -230,7 +230,7 @@ public void InsertText( public void InsertText(string textToInsert, IFileRange insertRange) { this.editorOperations - .InsertTextAsync(this.scriptFile.ClientFilePath, textToInsert, insertRange.ToBufferRange()) + .InsertTextAsync(this.scriptFile.DocumentUri.ToString(), textToInsert, insertRange.ToBufferRange()) .Wait(); } diff --git a/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs b/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs index 472d1157e..cfb49699b 100644 --- a/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs +++ b/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs @@ -13,7 +13,7 @@ using Microsoft.PowerShell.EditorServices.Services; using Serilog; using Serilog.Events; -using OmniSharp.Extensions.LanguageServer.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; #if DEBUG using Serilog.Debugging; @@ -126,7 +126,7 @@ public PsesDebugServer CreateDebugServerForTempSession(Stream inputStream, Strea .AddPsesLanguageServices(hostStartupInfo) // For a Temp session, there is no LanguageServer so just set it to null .AddSingleton( - typeof(OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer), + typeof(ILanguageServer), _ => null) .BuildServiceProvider(); diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index c49159cc9..7e28c7d94 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -40,6 +40,7 @@ + @@ -49,7 +50,6 @@ - diff --git a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs index ff94ecad7..8a3818dd5 100644 --- a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs +++ b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs @@ -10,6 +10,7 @@ using Microsoft.PowerShell.EditorServices.Handlers; using Microsoft.PowerShell.EditorServices.Hosting; using Microsoft.PowerShell.EditorServices.Services; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; using OmniSharp.Extensions.LanguageServer.Server; using Serilog; @@ -68,23 +69,23 @@ public async Task StartAsync() .AddSerilog(Log.Logger) .AddLanguageServer(_minimumLogLevel) .SetMinimumLevel(_minimumLogLevel)) - .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() - .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() .WithHandler() .WithHandler() diff --git a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs index 858441fa8..de4bcf01e 100644 --- a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -18,6 +17,7 @@ using Microsoft.PowerShell.EditorServices.Services.Configuration; using Microsoft.PowerShell.EditorServices.Services.TextDocument; using OmniSharp.Extensions.LanguageServer.Protocol; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; @@ -136,8 +136,7 @@ public AnalysisService( /// A cancellation token to cancel this call with. /// A task that finishes when script diagnostics have been published. public void RunScriptDiagnostics( - ScriptFile[] filesToAnalyze, - CancellationToken cancellationToken) + ScriptFile[] filesToAnalyze) { if (_configurationService.CurrentSettings.ScriptAnalysis.Enable == false) { @@ -146,10 +145,8 @@ public void RunScriptDiagnostics( EnsureEngineSettingsCurrent(); - // Create a cancellation token source that will cancel if we do or if the caller does - var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - // If there's an existing task, we want to cancel it here; + var cancellationSource = new CancellationTokenSource(); CancellationTokenSource oldTaskCancellation = Interlocked.Exchange(ref _diagnosticsCancellationTokenSource, cancellationSource); if (oldTaskCancellation != null) { @@ -420,9 +417,9 @@ private void PublishScriptDiagnostics(ScriptFile scriptFile, IReadOnlyList(diagnostics) }); } diff --git a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs index 557f43e9f..e6e025286 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs @@ -55,7 +55,7 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile Data = JToken.FromObject(new { Uri = scriptFile.DocumentUri, ProviderId = nameof(PesterCodeLensProvider) - }), + }, Serializer.Instance.JsonSerializer), Command = new Command() { Name = "PowerShell.RunPesterTests", @@ -66,8 +66,7 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile false /* No debug */, pesterSymbol.TestName, pesterSymbol.ScriptRegion?.StartLineNumber - }, - Serializer.Instance.JsonSerializer) + }, Serializer.Instance.JsonSerializer) } }, @@ -77,7 +76,7 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile Data = JToken.FromObject(new { Uri = scriptFile.DocumentUri, ProviderId = nameof(PesterCodeLensProvider) - }), + }, Serializer.Instance.JsonSerializer), Command = new Command() { Name = "PowerShell.RunPesterTests", diff --git a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs index edf5c7cff..82ae08b1a 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs @@ -68,7 +68,7 @@ public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { Uri = scriptFile.DocumentUri, ProviderId = nameof(ReferencesCodeLensProvider) - }), + }, Serializer.Instance.JsonSerializer), Range = sym.ScriptRegion.ToRange() }); } diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs index f50221c92..a1c7a030a 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs @@ -87,7 +87,7 @@ public SetExceptionBreakpointsHandler( DebugService debugService, DebugStateService debugStateService) { - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); _debugService = debugService; _debugStateService = debugStateService; } @@ -133,7 +133,7 @@ public SetBreakpointsHandler( DebugStateService debugStateService, WorkspaceService workspaceService) { - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); _debugService = debugService; _debugStateService = debugStateService; _workspaceService = workspaceService; diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs index 118f0a925..12e77552e 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs @@ -37,7 +37,7 @@ public ConfigurationDoneHandler( PowerShellContextService powerShellContextService, WorkspaceService workspaceService) { - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); _jsonRpcServer = jsonRpcServer; _debugService = debugService; _debugStateService = debugStateService; @@ -106,7 +106,7 @@ private async Task LaunchScriptAsync(string scriptToLaunch) // By doing this, we light up the ability to debug Untitled files with breakpoints. // This is only possible via the direct usage of the breakpoint APIs in PowerShell because // Set-PSBreakpoint validates that paths are actually on the filesystem. - ScriptBlockAst ast = Parser.ParseInput(untitledScript.Contents, untitledScript.DocumentUri, out Token[] tokens, out ParseError[] errors); + ScriptBlockAst ast = Parser.ParseInput(untitledScript.Contents, untitledScript.DocumentUri.ToString(), out Token[] tokens, out ParseError[] errors); // This seems to be the simplest way to invoke a script block (which contains breakpoint information) via the PowerShell API. var cmd = new PSCommand().AddScript(". $args[0]").AddArgument(ast.GetScriptBlock()); diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs index 5854d7a58..4528981ba 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs @@ -25,7 +25,7 @@ public VariablesHandler( ILoggerFactory loggerFactory, DebugService debugService) { - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); _debugService = debugService; } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs index 47b397400..93d8888cf 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs @@ -10,10 +10,10 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.PowerShell.EditorServices.Services; -using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Window; namespace Microsoft.PowerShell.EditorServices.Handlers { @@ -96,7 +96,7 @@ private async Task CheckPackageManagement() } var takeActionText = "Yes"; - MessageActionItem messageAction = await _languageServer.Window.ShowMessage(new ShowMessageRequestParams + MessageActionItem messageAction = await _languageServer.Window.ShowMessageRequest(new ShowMessageRequestParams { Message = "You have an older version of PackageManagement known to cause issues with the PowerShell extension. Would you like to update PackageManagement (You will need to restart the PowerShell extension after)?", Type = MessageType.Warning, diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/PSHostProcessAndRunspaceHandlers.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/PSHostProcessAndRunspaceHandlers.cs index 1b6ccc8f0..580045ce6 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/PSHostProcessAndRunspaceHandlers.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/PSHostProcessAndRunspaceHandlers.cs @@ -17,12 +17,12 @@ namespace Microsoft.PowerShell.EditorServices.Handlers internal class PSHostProcessAndRunspaceHandlers : IGetPSHostProcessesHandler, IGetRunspaceHandler { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly PowerShellContextService _powerShellContextService; public PSHostProcessAndRunspaceHandlers(ILoggerFactory factory, PowerShellContextService powerShellContextService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _powerShellContextService = powerShellContextService; } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/TemplateHandlers.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/TemplateHandlers.cs index 646c79358..4d31d79d5 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/TemplateHandlers.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/TemplateHandlers.cs @@ -14,14 +14,14 @@ namespace Microsoft.PowerShell.EditorServices.Handlers { internal class TemplateHandlers : IGetProjectTemplatesHandler, INewProjectFromTemplateHandler { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly TemplateService _templateService; public TemplateHandlers( ILoggerFactory factory, TemplateService templateService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _templateService = templateService; } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index e4508d13f..fbbfbc9dc 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -32,7 +32,7 @@ namespace Microsoft.PowerShell.EditorServices.Services /// Handles nested PowerShell prompts and also manages execution of /// commands whether inside or outside of the debugger. /// - internal class PowerShellContextService : IDisposable, IHostSupportsInteractiveSession + internal class PowerShellContextService : IHostSupportsInteractiveSession { private static readonly string s_commandsModulePath = Path.GetFullPath( Path.Combine( @@ -1402,11 +1402,12 @@ private void ResumeDebugger(DebuggerResumeAction resumeAction, bool shouldWaitFo } /// - /// Disposes the runspace and any other resources being used + /// Closes the runspace and any other resources being used /// by this PowerShellContext. /// - public void Dispose() + public void Close() { + logger.LogDebug("Closing PowerShellContextService..."); this.PromptNest.Dispose(); this.SessionState = PowerShellContextState.Disposed; diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindDeclarationVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindDeclarationVisitor.cs index 91f3671ff..3ef4fc1ed 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindDeclarationVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindDeclarationVisitor.cs @@ -50,7 +50,8 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, StartColumnNumber = startColumnNumber, EndLineNumber = functionDefinitionAst.Extent.StartLineNumber, - EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length + EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length, + File = functionDefinitionAst.Extent.File }; if (symbolRef.SymbolType.Equals(SymbolType.Function) && diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs index b8444fc64..63e6003d6 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs @@ -129,7 +129,8 @@ public override AstVisitAction VisitHashtable(HashtableAst hashtableAst) StartLineNumber = kvp.Item1.Extent.StartLineNumber, EndLineNumber = kvp.Item2.Extent.EndLineNumber, StartColumnNumber = kvp.Item1.Extent.StartColumnNumber, - EndColumnNumber = kvp.Item2.Extent.EndColumnNumber + EndColumnNumber = kvp.Item2.Extent.EndColumnNumber, + File = hashtableAst.Extent.File }; SymbolType symbolType = SymbolType.HashtableKey; diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index a054dbdf1..fc57045dd 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -14,12 +14,12 @@ using Microsoft.PowerShell.EditorServices.Utility; using Newtonsoft.Json.Linq; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class CodeActionHandler : ICodeActionHandler + internal class PsesCodeActionHandler : ICodeActionHandler { private static readonly CodeActionKind[] s_supportedCodeActions = new[] { @@ -36,9 +36,9 @@ internal class CodeActionHandler : ICodeActionHandler private CodeActionCapability _capability; - public CodeActionHandler(ILoggerFactory factory, AnalysisService analysisService, WorkspaceService workspaceService) + public PsesCodeActionHandler(ILoggerFactory factory, AnalysisService analysisService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _analysisService = analysisService; _workspaceService = workspaceService; _registrationOptions = new CodeActionRegistrationOptions diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs index 334b4b913..a43dac341 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs @@ -17,12 +17,12 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class CodeLensHandlers : ICodeLensHandler, ICodeLensResolveHandler + internal class PsesCodeLensHandlers : ICodeLensHandler, ICodeLensResolveHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; @@ -30,9 +30,9 @@ internal class CodeLensHandlers : ICodeLensHandler, ICodeLensResolveHandler private CodeLensCapability _capability; - public CodeLensHandlers(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService, ConfigurationService configurationService) + public PsesCodeLensHandlers(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService, ConfigurationService configurationService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _workspaceService = workspaceService; _symbolsService = symbolsService; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs index f01073733..421f766a3 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs @@ -16,12 +16,12 @@ using Microsoft.PowerShell.EditorServices.Services.TextDocument; using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class CompletionHandler : ICompletionHandler, ICompletionResolveHandler + internal class PsesCompletionHandler : ICompletionHandler, ICompletionResolveHandler { const int DefaultWaitTimeoutMilliseconds = 5000; private readonly SemaphoreSlim _completionLock = AsyncUtils.CreateSimpleLockingSemaphore(); @@ -41,12 +41,12 @@ internal class CompletionHandler : ICompletionHandler, ICompletionResolveHandler private CompletionCapability _capability; - public CompletionHandler( + public PsesCompletionHandler( ILoggerFactory factory, PowerShellContextService powerShellContextService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _powerShellContextService = powerShellContextService; _workspaceService = workspaceService; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs index 744b14128..25c384620 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs @@ -13,12 +13,12 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class DefinitionHandler : IDefinitionHandler + internal class PsesDefinitionHandler : IDefinitionHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; @@ -26,12 +26,12 @@ internal class DefinitionHandler : IDefinitionHandler private DefinitionCapability _capability; - public DefinitionHandler( + public PsesDefinitionHandler( ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _symbolsService = symbolsService; _workspaceService = workspaceService; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs index 6a57948d3..5daa111f5 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs @@ -9,15 +9,15 @@ using Microsoft.PowerShell.EditorServices.Services.TextDocument; using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class DocumentHighlightHandler : IDocumentHighlightHandler + internal class PsesDocumentHighlightHandler : IDocumentHighlightHandler { private static readonly DocumentHighlightContainer s_emptyHighlightContainer = new DocumentHighlightContainer(); @@ -29,12 +29,12 @@ internal class DocumentHighlightHandler : IDocumentHighlightHandler private DocumentHighlightCapability _capability; - public DocumentHighlightHandler( + public PsesDocumentHighlightHandler( ILoggerFactory loggerFactory, WorkspaceService workspaceService, SymbolsService symbolService) { - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); _workspaceService = workspaceService; _symbolsService = symbolService; _logger.LogInformation("highlight handler loaded"); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs index 743b721d3..bbf5d3109 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs @@ -18,12 +18,12 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class DocumentSymbolHandler : IDocumentSymbolHandler + internal class PsesDocumentSymbolHandler : IDocumentSymbolHandler { private readonly ILogger _logger; private readonly WorkspaceService _workspaceService; @@ -32,9 +32,9 @@ internal class DocumentSymbolHandler : IDocumentSymbolHandler private DocumentSymbolCapability _capability; - public DocumentSymbolHandler(ILoggerFactory factory, ConfigurationService configurationService, WorkspaceService workspaceService) + public PsesDocumentSymbolHandler(ILoggerFactory factory, ConfigurationService configurationService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _workspaceService = workspaceService; _providers = new IDocumentSymbolProvider[] { diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs index aafee5b36..1a9da9eae 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs @@ -12,11 +12,11 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class FoldingRangeHandler : IFoldingRangeHandler + internal class PsesFoldingRangeHandler : IFoldingRangeHandler { private readonly ILogger _logger; private readonly ConfigurationService _configurationService; @@ -24,7 +24,7 @@ internal class FoldingRangeHandler : IFoldingRangeHandler private FoldingRangeCapability _capability; - public FoldingRangeHandler(ILoggerFactory factory, ConfigurationService configurationService, WorkspaceService workspaceService) + public PsesFoldingRangeHandler(ILoggerFactory factory, ConfigurationService configurationService, WorkspaceService workspaceService) { _logger = factory.CreateLogger(); _configurationService = configurationService; diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs index 060f9c6c9..a229fbea9 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs @@ -10,13 +10,14 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { // TODO: Add IDocumentOnTypeFormatHandler to support on-type formatting. - internal class DocumentFormattingHandlers : IDocumentFormattingHandler, IDocumentRangeFormattingHandler + internal class PsesDocumentFormattingHandlers : IDocumentFormattingHandler, IDocumentRangeFormattingHandler { private readonly ILogger _logger; private readonly AnalysisService _analysisService; @@ -26,13 +27,13 @@ internal class DocumentFormattingHandlers : IDocumentFormattingHandler, IDocumen private DocumentFormattingCapability _documentFormattingCapability; private DocumentRangeFormattingCapability _documentRangeFormattingCapability; - public DocumentFormattingHandlers( + public PsesDocumentFormattingHandlers( ILoggerFactory factory, AnalysisService analysisService, ConfigurationService configurationService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _analysisService = analysisService; _configurationService = configurationService; _workspaceService = workspaceService; diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs index 2d3065906..ad2174487 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs @@ -12,12 +12,12 @@ using Microsoft.PowerShell.EditorServices.Services.TextDocument; using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class HoverHandler : IHoverHandler + internal class PsesHoverHandler : IHoverHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; @@ -25,12 +25,12 @@ internal class HoverHandler : IHoverHandler private HoverCapability _capability; - public HoverHandler( + public PsesHoverHandler( ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _symbolsService = symbolsService; _workspaceService = workspaceService; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs index 61ba070e0..18b7b34ca 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs @@ -13,21 +13,21 @@ using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - class ReferencesHandler : IReferencesHandler + class PsesReferencesHandler : IReferencesHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; private readonly WorkspaceService _workspaceService; private ReferenceCapability _capability; - public ReferencesHandler(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService) + public PsesReferencesHandler(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _symbolsService = symbolsService; _workspaceService = workspaceService; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/SignatureHelpHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/SignatureHelpHandler.cs index 31ae18368..688e5aba7 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/SignatureHelpHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/SignatureHelpHandler.cs @@ -12,12 +12,12 @@ using Microsoft.PowerShell.EditorServices.Services.TextDocument; using Microsoft.PowerShell.EditorServices.Utility; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class SignatureHelpHandler : ISignatureHelpHandler + internal class PsesSignatureHelpHandler : ISignatureHelpHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; @@ -26,13 +26,13 @@ internal class SignatureHelpHandler : ISignatureHelpHandler private SignatureHelpCapability _capability; - public SignatureHelpHandler( + public PsesSignatureHelpHandler( ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService, PowerShellContextService powerShellContextService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _symbolsService = symbolsService; _workspaceService = workspaceService; _powerShellContextService = powerShellContextService; diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs index c5b9f861e..e5961c9a8 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs @@ -13,13 +13,13 @@ using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities; using Microsoft.PowerShell.EditorServices.Utility; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; namespace Microsoft.PowerShell.EditorServices.Handlers { - class TextDocumentHandler : ITextDocumentSyncHandler + class PsesTextDocumentHandler : ITextDocumentSyncHandler { private static readonly Uri s_fakeUri = new Uri("Untitled:fake"); @@ -31,13 +31,13 @@ class TextDocumentHandler : ITextDocumentSyncHandler public TextDocumentSyncKind Change => TextDocumentSyncKind.Incremental; - public TextDocumentHandler( + public PsesTextDocumentHandler( ILoggerFactory factory, AnalysisService analysisService, WorkspaceService workspaceService, RemoteFileManagerService remoteFileManagerService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _analysisService = analysisService; _workspaceService = workspaceService; _remoteFileManagerService = remoteFileManagerService; @@ -58,7 +58,7 @@ public Task Handle(DidChangeTextDocumentParams notification, CancellationT // Kick off script diagnostics without blocking the response // TODO: Get all recently edited files in the workspace - _analysisService.RunScriptDiagnostics(new ScriptFile[] { changedFile }, token); + _analysisService.RunScriptDiagnostics(new ScriptFile[] { changedFile }); return Unit.Task; } @@ -91,7 +91,7 @@ public Task Handle(DidOpenTextDocumentParams notification, CancellationTok { // Kick off script diagnostics if we got a PowerShell file without blocking the response // TODO: Get all recently edited files in the workspace - _analysisService.RunScriptDiagnostics(new ScriptFile[] { openedFile }, token); + _analysisService.RunScriptDiagnostics(new ScriptFile[] { openedFile }); } _logger.LogTrace("Finished opening document."); diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs index 50775a579..8a40b04e7 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs @@ -11,6 +11,7 @@ using System.Management.Automation.Language; using Microsoft.PowerShell.EditorServices.Services.Symbols; using Microsoft.PowerShell.EditorServices.Utility; +using OmniSharp.Extensions.LanguageServer.Protocol; namespace Microsoft.PowerShell.EditorServices.Services.TextDocument { @@ -48,24 +49,10 @@ public string Id /// public string FilePath { get; private set; } - /// - /// Gets the path which the editor client uses to identify this file. - /// - public string ClientFilePath { get; private set; } - /// /// Gets the file path in LSP DocumentUri form. The ClientPath property must not be null. /// - public string DocumentUri - { - get - { - // TODO: Have this be a DocumentUri type and stop having it be computed every time. - return this.ClientFilePath == null - ? string.Empty - : OmniSharp.Extensions.LanguageServer.Protocol.DocumentUri.FromFileSystemPath(ClientFilePath)?.ToString(); - } - } + public DocumentUri DocumentUri { get; set; } /// /// Gets or sets a boolean that determines whether @@ -151,11 +138,11 @@ public string[] ReferencedFiles /// Creates a new ScriptFile instance by reading file contents from /// the given TextReader. /// - /// The System.Uri of the file. + /// The System.Uri of the file. /// The TextReader to use for reading the file's contents. /// The version of PowerShell for which the script is being parsed. internal ScriptFile( - Uri fileUri, + DocumentUri docUri, TextReader textReader, Version powerShellVersion) { @@ -163,16 +150,16 @@ internal ScriptFile( // so that other operations know it's untitled/in-memory // and don't think that it's a relative path // on the file system. - this.FilePath = fileUri.IsFile - ? fileUri.LocalPath - : fileUri.OriginalString; - this.ClientFilePath = fileUri.OriginalString; - this.IsAnalysisEnabled = true; - this.IsInMemory = !fileUri.IsFile; + IsInMemory = !docUri.ToUri().IsFile; + FilePath = IsInMemory + ? docUri.ToString() + : docUri.GetFileSystemPath(); + DocumentUri = docUri; + IsAnalysisEnabled = true; this.powerShellVersion = powerShellVersion; // SetFileContents() calls ParseFileContents() which initializes the rest of the properties. - this.SetFileContents(textReader.ReadToEnd()); + SetFileContents(textReader.ReadToEnd()); } /// @@ -182,7 +169,7 @@ internal ScriptFile( /// The initial contents of the script file. /// The version of PowerShell for which the script is being parsed. internal ScriptFile( - Uri fileUri, + DocumentUri fileUri, string initialBuffer, Version powerShellVersion) : this( @@ -633,7 +620,7 @@ private void ParseFileContents() // Discussed in https://github.com/PowerShell/PowerShellEditorServices/pull/815. // Rather than working hard to enable things for untitled files like a phantom directory, // users should save the file. - if (IsUntitledPath(this.FilePath)) + if (IsInMemory) { // Need to initialize the ReferencedFiles property to an empty array. this.ReferencedFiles = Array.Empty(); diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs index b77b327ca..bf39a1f3f 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs @@ -13,11 +13,11 @@ using MediatR; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class ConfigurationHandler : IDidChangeConfigurationHandler + internal class PsesConfigurationHandler : IDidChangeConfigurationHandler { private readonly ILogger _logger; private readonly WorkspaceService _workspaceService; @@ -27,14 +27,14 @@ internal class ConfigurationHandler : IDidChangeConfigurationHandler private bool _profilesLoaded; private bool _consoleReplStarted; - public ConfigurationHandler( + public PsesConfigurationHandler( ILoggerFactory factory, WorkspaceService workspaceService, AnalysisService analysisService, ConfigurationService configurationService, PowerShellContextService powerShellContextService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _workspaceService = workspaceService; _configurationService = configurationService; _powerShellContextService = powerShellContextService; diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs index c35989a24..642a13dc4 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs @@ -15,19 +15,19 @@ using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; namespace Microsoft.PowerShell.EditorServices.Handlers { - internal class WorkspaceSymbolsHandler : IWorkspaceSymbolsHandler + internal class PsesWorkspaceSymbolsHandler : IWorkspaceSymbolsHandler { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; private readonly WorkspaceService _workspaceService; private WorkspaceSymbolCapability _capability; - public WorkspaceSymbolsHandler(ILoggerFactory loggerFactory, SymbolsService symbols, WorkspaceService workspace) { - _logger = loggerFactory.CreateLogger(); + public PsesWorkspaceSymbolsHandler(ILoggerFactory loggerFactory, SymbolsService symbols, WorkspaceService workspace) { + _logger = loggerFactory.CreateLogger(); _symbolsService = symbols; _workspaceService = workspace; } diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs index d75766bb5..44f8b8820 100644 --- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs @@ -154,7 +154,7 @@ public ScriptFile GetFile(DocumentUri documentUri) { scriptFile = new ScriptFile( - documentUri.ToUri(), + documentUri, streamReader, this.powerShellVersion); @@ -274,7 +274,7 @@ public ScriptFile GetFileBuffer(DocumentUri documentUri, string initialBuffer) { scriptFile = new ScriptFile( - documentUri.ToUri(), + documentUri, initialBuffer, this.powerShellVersion); diff --git a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs index b59101e87..11ea4a49a 100644 --- a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs +++ b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs @@ -2,12 +2,19 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using OmniSharp.Extensions.LanguageServer.Client; -using OmniSharp.Extensions.LanguageServer.Client.Processes; +using OmniSharp.Extensions.LanguageServer.Protocol; +using OmniSharp.Extensions.LanguageServer.Protocol.Client; +using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Window; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; +using Xunit.Abstractions; namespace PowerShellEditorServices.Test.E2E { @@ -15,22 +22,53 @@ public class LSPTestsFixture : TestsFixture { public override bool IsDebugAdapterTests => false; - public LanguageClient LanguageClient { get; private set; } + public ILanguageClient PsesLanguageClient { get; private set; } public List Diagnostics { get; set; } + public ITestOutputHelper Output { get; set; } + public async override Task CustomInitializeAsync( ILoggerFactory factory, - StdioServerProcess process) + Stream inputStream, + Stream outputStream) { - LanguageClient = new LanguageClient(factory, process); - + Diagnostics = new List(); DirectoryInfo testdir = Directory.CreateDirectory(Path.Combine(s_binDir, Path.GetRandomFileName())); - await LanguageClient.Initialize(testdir.FullName); + PsesLanguageClient = LanguageClient.PreInit(options => + { + options + .WithInput(inputStream) + .WithOutput(outputStream) + .WithRootUri(DocumentUri.FromFileSystemPath(testdir.FullName)) + .OnPublishDiagnostics(diagnosticParams => + { + Diagnostics.AddRange(diagnosticParams.Diagnostics.Where(d => d != null)); + }) + .OnLogMessage(logMessageParams => + { + Output?.WriteLine($"{logMessageParams.Type.ToString()}: {logMessageParams.Message}"); + }); + + // Enable all capabilities this this is for testing. + // This will be a built in feature of the Omnisharp client at some point. + var capabilityTypes = typeof(ICapability).Assembly.GetExportedTypes() + .Where(z => typeof(ICapability).IsAssignableFrom(z)) + .Where(z => z.IsClass && !z.IsAbstract); + foreach (Type capabilityType in capabilityTypes) + { + options.WithCapability(Activator.CreateInstance(capabilityType, Array.Empty()) as ICapability); + } + }); + + await PsesLanguageClient.Initialize(CancellationToken.None); // Make sure Script Analysis is enabled because we'll need it in the tests. - LanguageClient.Workspace.DidChangeConfiguration(JObject.Parse(@" + PsesLanguageClient.Workspace.DidChangeConfiguration( + new DidChangeConfigurationParams + { + Settings = JObject.Parse(@" { ""powershell"": { ""scriptAnalysis"": { @@ -38,22 +76,17 @@ public async override Task CustomInitializeAsync( } } } -")); - - Diagnostics = new List(); - LanguageClient.TextDocument.OnPublishDiagnostics((uri, diagnostics) => - { - Diagnostics.AddRange(diagnostics.Where(d => d != null)); - }); +") + }); } public override async Task DisposeAsync() { try { - await LanguageClient.Shutdown(); + await PsesLanguageClient.Shutdown(); await _psesProcess.Stop(); - LanguageClient?.Dispose(); + PsesLanguageClient?.Dispose(); } catch (ObjectDisposedException) { diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index b7bb8f679..05826f514 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -14,8 +14,11 @@ using System.Threading.Tasks; using Microsoft.PowerShell.EditorServices.Handlers; using Newtonsoft.Json.Linq; -using OmniSharp.Extensions.LanguageServer.Client; +using OmniSharp.Extensions.LanguageServer.Protocol; +using OmniSharp.Extensions.LanguageServer.Protocol.Client; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; using Xunit; using Xunit.Abstractions; using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; @@ -29,30 +32,18 @@ public class LanguageServerProtocolMessageTests : IClassFixture private static bool s_registeredOnLogMessage; - private readonly LanguageClient LanguageClient; + private readonly ILanguageClient PsesLanguageClient; private readonly List Diagnostics; private readonly string PwshExe; - private readonly ITestOutputHelper _output; public LanguageServerProtocolMessageTests(ITestOutputHelper output, LSPTestsFixture data) { - LanguageClient = data.LanguageClient; + data.Output = output; + PsesLanguageClient = data.PsesLanguageClient; Diagnostics = data.Diagnostics; Diagnostics.Clear(); PwshExe = TestsFixture.PwshExe; - - _output = output; - - if (!s_registeredOnLogMessage) - { - LanguageClient.Window.OnLogMessage((message, messageType) => - { - _output.WriteLine($"{messageType.ToString()}: {message}"); - }); - - s_registeredOnLogMessage = true; - } } public void Dispose() @@ -66,7 +57,7 @@ private string NewTestFile(string script, bool isPester = false, string language string filePath = Path.Combine(s_binDir, Path.GetRandomFileName() + fileExt); File.WriteAllText(filePath, script); - LanguageClient.SendNotification("textDocument/didOpen", new DidOpenTextDocumentParams + PsesLanguageClient.SendNotification("textDocument/didOpen", new DidOpenTextDocumentParams { TextDocument = new TextDocumentItem { @@ -103,7 +94,9 @@ private async Task WaitForDiagnostics() public async Task CanSendPowerShellGetVersionRequest() { PowerShellVersion details - = await LanguageClient.SendRequest("powerShell/getVersion", new GetVersionParams()); + = await PsesLanguageClient + .SendRequest("powerShell/getVersion", new GetVersionParams()) + .Returning(CancellationToken.None); if(PwshExe == "powershell") { @@ -125,12 +118,14 @@ function CanSendWorkspaceSymbolRequest { } "); - Container symbols = await LanguageClient.SendRequest>( - "workspace/symbol", - new WorkspaceSymbolParams - { - Query = "CanSendWorkspaceSymbolRequest" - }); + Container symbols = await PsesLanguageClient + .SendRequest( + "workspace/symbol", + new WorkspaceSymbolParams + { + Query = "CanSendWorkspaceSymbolRequest" + }) + .Returning>(CancellationToken.None); SymbolInformation symbol = Assert.Single(symbols); Assert.Equal("CanSendWorkspaceSymbolRequest { }", symbol.Name); @@ -170,7 +165,7 @@ public async Task CanReceiveDiagnosticsFromFileChanged() await WaitForDiagnostics(); Diagnostics.Clear(); - LanguageClient.SendNotification("textDocument/didChange", new DidChangeTextDocumentParams + PsesLanguageClient.SendNotification("textDocument/didChange", new DidChangeTextDocumentParams { // Include several content changes to test against duplicate Diagnostics showing up. ContentChanges = new Container(new [] @@ -226,7 +221,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChange() try { - LanguageClient.SendNotification("workspace/didChangeConfiguration", + PsesLanguageClient.SendNotification("workspace/didChangeConfiguration", new DidChangeConfigurationParams { Settings = JToken.Parse(@" @@ -244,7 +239,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChange() } finally { - LanguageClient.SendNotification("workspace/didChangeConfiguration", + PsesLanguageClient.SendNotification("workspace/didChangeConfiguration", new DidChangeConfigurationParams { Settings = JToken.Parse(@" @@ -272,15 +267,17 @@ public async Task CanSendFoldingRangeRequest() }"); Container foldingRanges = - await LanguageClient.SendRequest>( - "textDocument/foldingRange", - new FoldingRangeRequestParam - { - TextDocument = new TextDocumentIdentifier + await PsesLanguageClient + .SendRequest( + "textDocument/foldingRange", + new FoldingRangeRequestParam { - Uri = new Uri(scriptPath) - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + } + }) + .Returning>(CancellationToken.None); Assert.Collection(foldingRanges.OrderBy(f => f.StartLine), range1 => @@ -313,20 +310,22 @@ public async Task CanSendFormattingRequest() "); - TextEditContainer textEdits = await LanguageClient.SendRequest( - "textDocument/formatting", - new DocumentFormattingParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = new Uri(scriptPath) - }, - Options = new FormattingOptions + TextEditContainer textEdits = await PsesLanguageClient + .SendRequest( + "textDocument/formatting", + new DocumentFormattingParams { - TabSize = 4, - InsertSpaces = false - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + }, + Options = new FormattingOptions + { + TabSize = 4, + InsertSpaces = false + } + }) + .Returning(CancellationToken.None); TextEdit textEdit = Assert.Single(textEdits); @@ -348,33 +347,35 @@ public async Task CanSendRangeFormattingRequest() "); - TextEditContainer textEdits = await LanguageClient.SendRequest( - "textDocument/formatting", - new DocumentRangeFormattingParams - { - Range = new Range - { - Start = new Position - { - Line = 2, - Character = 0 - }, - End = new Position - { - Line = 3, - Character = 0 - } - }, - TextDocument = new TextDocumentIdentifier + TextEditContainer textEdits = await PsesLanguageClient + .SendRequest( + "textDocument/formatting", + new DocumentRangeFormattingParams { - Uri = new Uri(scriptPath) - }, - Options = new FormattingOptions - { - TabSize = 4, - InsertSpaces = false - } - }); + Range = new Range + { + Start = new Position + { + Line = 2, + Character = 0 + }, + End = new Position + { + Line = 3, + Character = 0 + } + }, + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + }, + Options = new FormattingOptions + { + TabSize = 4, + InsertSpaces = false + } + }) + .Returning(CancellationToken.None); TextEdit textEdit = Assert.Single(textEdits); @@ -394,15 +395,17 @@ function CanSendDocumentSymbolRequest { "); SymbolInformationOrDocumentSymbolContainer symbolInformationOrDocumentSymbols = - await LanguageClient.SendRequest( - "textDocument/documentSymbol", - new DocumentSymbolParams - { - TextDocument = new TextDocumentIdentifier + await PsesLanguageClient + .SendRequest( + "textDocument/documentSymbol", + new DocumentSymbolParams { - Uri = new Uri(scriptPath) - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + } + }) + .Returning(CancellationToken.None); Assert.Collection(symbolInformationOrDocumentSymbols, symInfoOrDocSym => { @@ -426,24 +429,26 @@ function CanSendReferencesRequest { CanSendReferencesRequest "); - LocationContainer locations = await LanguageClient.SendRequest( - "textDocument/references", - new ReferenceParams - { - TextDocument = new TextDocumentIdentifier + LocationContainer locations = await PsesLanguageClient + .SendRequest( + "textDocument/references", + new ReferenceParams { - Uri = new Uri(scriptPath) - }, - Position = new Position - { - Line = 5, - Character = 0 - }, - Context = new ReferenceContext - { - IncludeDeclaration = false - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + }, + Position = new Position + { + Line = 5, + Character = 0 + }, + Context = new ReferenceContext + { + IncludeDeclaration = false + } + }) + .Returning(CancellationToken.None); Assert.Collection(locations, location1 => @@ -475,20 +480,22 @@ public async Task CanSendDocumentHighlightRequest() "); DocumentHighlightContainer documentHighlights = - await LanguageClient.SendRequest( - "textDocument/documentHighlight", - new DocumentHighlightParams - { - TextDocument = new TextDocumentIdentifier + await PsesLanguageClient + .SendRequest( + "textDocument/documentHighlight", + new DocumentHighlightParams { - Uri = new Uri(scriptPath) - }, - Position = new Position - { - Line = 3, - Character = 1 - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + }, + Position = new Position + { + Line = 3, + Character = 1 + } + }) + .Returning(CancellationToken.None); Assert.Collection(documentHighlights, documentHighlight1 => @@ -536,9 +543,11 @@ public async Task CanSendPowerShellGetPSHostProcessesRequest() try { pSHostProcessResponses = - await LanguageClient.SendRequest( - "powerShell/getPSHostProcesses", - new GetPSHostProcesssesParams { }); + await PsesLanguageClient + .SendRequest( + "powerShell/getPSHostProcesses", + new GetPSHostProcesssesParams { }) + .Returning(CancellationToken.None); } finally { @@ -574,12 +583,14 @@ public async Task CanSendPowerShellGetRunspaceRequest() try { runspaceResponses = - await LanguageClient.SendRequest( - "powerShell/getRunspace", - new GetRunspaceParams - { - ProcessId = $"{process.Id}" - }); + await PsesLanguageClient + .SendRequest( + "powerShell/getRunspace", + new GetRunspaceParams + { + ProcessId = $"{process.Id}" + }) + .Returning(CancellationToken.None); } finally { @@ -594,7 +605,10 @@ await LanguageClient.SendRequest( public async Task CanSendPesterLegacyCodeLensRequest() { // Make sure LegacyCodeLens is enabled because we'll need it in this test. - LanguageClient.Workspace.DidChangeConfiguration(JObject.Parse(@" + PsesLanguageClient.Workspace.DidChangeConfiguration( + new DidChangeConfigurationParams + { + Settings = JObject.Parse(@" { ""powershell"": { ""pester"": { @@ -602,7 +616,8 @@ public async Task CanSendPesterLegacyCodeLensRequest() } } } -")); +") + }); string filePath = NewTestFile(@" Describe 'DescribeName' { @@ -614,15 +629,17 @@ public async Task CanSendPesterLegacyCodeLensRequest() } ", isPester: true); - CodeLensContainer codeLenses = await LanguageClient.SendRequest( - "textDocument/codeLens", - new CodeLensParams - { - TextDocument = new TextDocumentIdentifier + CodeLensContainer codeLenses = await PsesLanguageClient + .SendRequest( + "textDocument/codeLens", + new CodeLensParams { - Uri = new Uri(filePath) - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(filePath) + } + }) + .Returning(CancellationToken.None); Assert.Collection(codeLenses, codeLens1 => @@ -653,15 +670,19 @@ public async Task CanSendPesterLegacyCodeLensRequest() public async Task CanSendPesterCodeLensRequest() { // Make sure Pester legacy CodeLens is disabled because we'll need it in this test. - LanguageClient.Workspace.DidChangeConfiguration(JObject.Parse(@" - { - ""powershell"": { - ""pester"": { - ""useLegacyCodeLens"": false - } - } - } - ")); + PsesLanguageClient.Workspace.DidChangeConfiguration( + new DidChangeConfigurationParams + { + Settings = JObject.Parse(@" +{ + ""powershell"": { + ""pester"": { + ""useLegacyCodeLens"": false + } + } +} +") + }); string filePath = NewTestFile(@" Describe 'DescribeName' { @@ -673,15 +694,17 @@ public async Task CanSendPesterCodeLensRequest() } ", isPester: true); - CodeLensContainer codeLenses = await LanguageClient.SendRequest( - "textDocument/codeLens", - new CodeLensParams - { - TextDocument = new TextDocumentIdentifier + CodeLensContainer codeLenses = await PsesLanguageClient + .SendRequest( + "textDocument/codeLens", + new CodeLensParams { - Uri = new Uri(filePath) - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(filePath) + } + }) + .Returning(CancellationToken.None); Assert.Collection(codeLenses, codeLens => @@ -763,15 +786,17 @@ function CanSendReferencesCodeLensRequest { CanSendReferencesCodeLensRequest "); - CodeLensContainer codeLenses = await LanguageClient.SendRequest( - "textDocument/codeLens", - new CodeLensParams - { - TextDocument = new TextDocumentIdentifier + CodeLensContainer codeLenses = await PsesLanguageClient + .SendRequest( + "textDocument/codeLens", + new CodeLensParams { - Uri = new Uri(filePath) - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(filePath) + } + }) + .Returning(CancellationToken.None); CodeLens codeLens = Assert.Single(codeLenses); @@ -781,9 +806,9 @@ function CanSendReferencesCodeLensRequest { Assert.Equal(3, range.End.Line); Assert.Equal(1, range.End.Character); - CodeLens codeLensResolveResult = await LanguageClient.SendRequest( - "codeLens/resolve", - codeLens); + CodeLens codeLensResolveResult = await PsesLanguageClient + .SendRequest("codeLens/resolve", codeLens) + .Returning(CancellationToken.None); Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } @@ -799,30 +824,32 @@ public async Task CanSendCodeActionRequest() await WaitForDiagnostics(); CommandOrCodeActionContainer commandOrCodeActions = - await LanguageClient.SendRequest( - "textDocument/codeAction", - new CodeActionParams - { - TextDocument = new TextDocumentIdentifier( - new Uri(filePath, UriKind.Absolute)), - Range = new Range + await PsesLanguageClient + .SendRequest( + "textDocument/codeAction", + new CodeActionParams { - Start = new Position + TextDocument = new TextDocumentIdentifier( + new Uri(filePath, UriKind.Absolute)), + Range = new Range { - Line = 0, - Character = 0 + Start = new Position + { + Line = 0, + Character = 0 + }, + End = new Position + { + Line = 0, + Character = 3 + } }, - End = new Position + Context = new CodeActionContext { - Line = 0, - Character = 3 + Diagnostics = new Container(Diagnostics) } - }, - Context = new CodeActionContext - { - Diagnostics = new Container(Diagnostics) - } - }); + }) + .Returning(CancellationToken.None); Assert.Collection(commandOrCodeActions, command => @@ -848,15 +875,22 @@ public async Task CanSendCompletionAndCompletionResolveRequest() { string filePath = NewTestFile("Write-H"); - CompletionList completionItems = await LanguageClient.TextDocument.Completions( - filePath, line: 0, column: 7); + CompletionList completionItems = await PsesLanguageClient.TextDocument.RequestCompletion( + new CompletionParams + { + TextDocument = new TextDocumentIdentifier + { + Uri = DocumentUri.FromFileSystemPath(filePath) + }, + Position = new Position(line: 0, character: 7) + }); CompletionItem completionItem = Assert.Single(completionItems, completionItem1 => completionItem1.Label == "Write-Host"); - CompletionItem updatedCompletionItem = await LanguageClient.SendRequest( - "completionItem/resolve", - completionItem); + CompletionItem updatedCompletionItem = await PsesLanguageClient + .SendRequest("completionItem/resolve", completionItem) + .Returning(CancellationToken.None); Assert.Contains("Writes customized output to a host", updatedCompletionItem.Documentation.String); } @@ -864,24 +898,33 @@ public async Task CanSendCompletionAndCompletionResolveRequest() [Fact] public async Task CanSendCompletionResolveWithModulePrefixRequest() { - await LanguageClient.SendRequest( - "evaluate", - new EvaluateRequestArguments - { - Expression = "Import-Module Microsoft.PowerShell.Archive -Prefix Slow" - }); + await PsesLanguageClient + .SendRequest( + "evaluate", + new EvaluateRequestArguments + { + Expression = "Import-Module Microsoft.PowerShell.Archive -Prefix Slow" + }) + .ReturningVoid(CancellationToken.None); string filePath = NewTestFile("Expand-SlowArch"); - CompletionList completionItems = await LanguageClient.TextDocument.Completions( - filePath, line: 0, column: 15); + CompletionList completionItems = await PsesLanguageClient.TextDocument.RequestCompletion( + new CompletionParams + { + TextDocument = new TextDocumentIdentifier + { + Uri = DocumentUri.FromFileSystemPath(filePath) + }, + Position = new Position(line: 0, character: 15) + }); CompletionItem completionItem = Assert.Single(completionItems, completionItem1 => completionItem1.Label == "Expand-SlowArchive"); - CompletionItem updatedCompletionItem = await LanguageClient.SendRequest( - "completionItem/resolve", - completionItem); + CompletionItem updatedCompletionItem = await PsesLanguageClient + .SendRequest("completionItem/resolve", completionItem) + .Returning(CancellationToken.None); Assert.Contains("Extracts files from a specified archive", updatedCompletionItem.Documentation.String); } @@ -891,7 +934,15 @@ public async Task CanSendHoverRequest() { string filePath = NewTestFile("Write-Host"); - Hover hover = await LanguageClient.TextDocument.Hover(filePath, line: 0, column: 1); + Hover hover = await PsesLanguageClient.TextDocument.RequestHover( + new HoverParams + { + TextDocument = new TextDocumentIdentifier + { + Uri = DocumentUri.FromFileSystemPath(filePath) + }, + Position = new Position(line: 0, character: 1) + }); Assert.True(hover.Contents.HasMarkedStrings); Assert.Collection(hover.Contents.MarkedStrings, @@ -911,20 +962,22 @@ public async Task CanSendSignatureHelpRequest() { string filePath = NewTestFile("Get-Date "); - SignatureHelp signatureHelp = await LanguageClient.SendRequest( - "textDocument/signatureHelp", - new SignatureHelpParams - { - TextDocument = new TextDocumentIdentifier + SignatureHelp signatureHelp = await PsesLanguageClient + .SendRequest( + "textDocument/signatureHelp", + new SignatureHelpParams { - Uri = new Uri(filePath) - }, - Position = new Position - { - Line = 0, - Character = 9 - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(filePath) + }, + Position = new Position + { + Line = 0, + Character = 9 + } + }) + .Returning(CancellationToken.None); Assert.Contains("Get-Date", signatureHelp.Signatures.First().Label); } @@ -941,20 +994,22 @@ function CanSendDefinitionRequest { "); LocationOrLocationLinks locationOrLocationLinks = - await LanguageClient.SendRequest( - "textDocument/definition", - new DefinitionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = new Uri(scriptPath) - }, - Position = new Position + await PsesLanguageClient + .SendRequest( + "textDocument/definition", + new DefinitionParams { - Line = 5, - Character = 2 - } - }); + TextDocument = new TextDocumentIdentifier + { + Uri = new Uri(scriptPath) + }, + Position = new Position + { + Line = 5, + Character = 2 + } + }) + .Returning(CancellationToken.None); LocationOrLocationLink locationOrLocationLink = Assert.Single(locationOrLocationLinks); @@ -971,12 +1026,14 @@ public async Task CanSendGetProjectTemplatesRequest() Skip.If(TestsFixture.RunningInConstainedLanguageMode, "Plaster doesn't work in ConstrainedLanguage mode."); GetProjectTemplatesResponse getProjectTemplatesResponse = - await LanguageClient.SendRequest( - "powerShell/getProjectTemplates", - new GetProjectTemplatesRequest - { - IncludeInstalledModules = true - }); + await PsesLanguageClient + .SendRequest( + "powerShell/getProjectTemplates", + new GetProjectTemplatesRequest + { + IncludeInstalledModules = true + }) + .Returning(CancellationToken.None); Assert.Collection(getProjectTemplatesResponse.Templates.OrderBy(t => t.Title), template1 => @@ -1010,18 +1067,20 @@ function CanSendGetCommentHelpRequest { "); CommentHelpRequestResult commentHelpRequestResult = - await LanguageClient.SendRequest( - "powerShell/getCommentHelp", - new CommentHelpRequestParams - { - DocumentUri = new Uri(scriptPath).ToString(), - BlockComment = false, - TriggerPosition = new Position + await PsesLanguageClient + .SendRequest( + "powerShell/getCommentHelp", + new CommentHelpRequestParams { - Line = 0, - Character = 0 - } - }); + DocumentUri = new Uri(scriptPath).ToString(), + BlockComment = false, + TriggerPosition = new Position + { + Line = 0, + Character = 0 + } + }) + .Returning(CancellationToken.None); Assert.NotEmpty(commentHelpRequestResult.Content); Assert.Contains("myParam", commentHelpRequestResult.Content[7]); @@ -1031,12 +1090,14 @@ await LanguageClient.SendRequest( public async Task CanSendEvaluateRequest() { EvaluateResponseBody evaluateResponseBody = - await LanguageClient.SendRequest( - "evaluate", - new EvaluateRequestArguments - { - Expression = "Get-ChildItem" - }); + await PsesLanguageClient + .SendRequest( + "evaluate", + new EvaluateRequestArguments + { + Expression = "Get-ChildItem" + }) + .Returning(CancellationToken.None); // These always gets returned so this test really just makes sure we get _any_ response. Assert.Equal("", evaluateResponseBody.Result); @@ -1047,7 +1108,9 @@ await LanguageClient.SendRequest( public async Task CanSendGetCommandRequest() { List pSCommandMessages = - await LanguageClient.SendRequest>("powerShell/getCommand", new GetCommandParams()); + await PsesLanguageClient + .SendRequest("powerShell/getCommand", new GetCommandParams()) + .Returning>(CancellationToken.None); Assert.NotEmpty(pSCommandMessages); // There should be at least 20 commands or so. @@ -1062,13 +1125,14 @@ public async Task CanSendExpandAliasRequest() "This feature currently doesn't support ConstrainedLanguage Mode."); ExpandAliasResult expandAliasResult = - await LanguageClient.SendRequest( - "powerShell/expandAlias", - new ExpandAliasParams - { - Text = "gci" - } - ); + await PsesLanguageClient + .SendRequest( + "powerShell/expandAlias", + new ExpandAliasParams + { + Text = "gci" + }) + .Returning(CancellationToken.None); Assert.Equal("Get-ChildItem", expandAliasResult.Text); } diff --git a/test/PowerShellEditorServices.Test.E2E/Processes/ServerProcess.cs b/test/PowerShellEditorServices.Test.E2E/Processes/ServerProcess.cs new file mode 100644 index 000000000..fe8a499e9 --- /dev/null +++ b/test/PowerShellEditorServices.Test.E2E/Processes/ServerProcess.cs @@ -0,0 +1,140 @@ +using System; +using System.IO; +using System.Reactive.Subjects; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace PowerShellEditorServices.Test.E2E +{ + /// + /// A is responsible for launching or attaching to a language server, providing access to its input and output streams, and tracking its lifetime. + /// + public abstract class ServerProcess : IDisposable + { + private readonly ISubject _exitedSubject; + /// + /// Create a new . + /// + /// + /// The factory for loggers used by the process and its components. + /// + protected ServerProcess(ILoggerFactory loggerFactory) + { + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + LoggerFactory = loggerFactory; + Log = LoggerFactory.CreateLogger(categoryName: GetType().FullName); + + ServerStartCompletion = new TaskCompletionSource(); + + ServerExitCompletion = new TaskCompletionSource(); + ServerExitCompletion.SetResult(null); // Start out as if the server has already exited. + + Exited = _exitedSubject = new AsyncSubject(); + } + + /// + /// Finaliser for . + /// + ~ServerProcess() + { + Dispose(false); + } + + /// + /// Dispose of resources being used by the launcher. + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Dispose of resources being used by the launcher. + /// + /// + /// Explicit disposal? + /// + protected virtual void Dispose(bool disposing) + { + } + + /// + /// The factory for loggers used by the process and its components. + /// + protected ILoggerFactory LoggerFactory { get; } + + /// + /// The process's logger. + /// + protected ILogger Log { get; } + + /// + /// The used to signal server startup. + /// + protected TaskCompletionSource ServerStartCompletion { get; set; } + + /// + /// The used to signal server exit. + /// + protected TaskCompletionSource ServerExitCompletion { get; set; } + + /// + /// Event raised when the server has exited. + /// + public IObservable Exited { get; } + + /// + /// Is the server running? + /// + public abstract bool IsRunning { get; } + + /// + /// A that completes when the server has started. + /// + public Task HasStarted => ServerStartCompletion.Task; + + /// + /// A that completes when the server has exited. + /// + public Task HasExited => ServerExitCompletion.Task; + + /// + /// The server's input stream. + /// + /// + /// The connection will write to the server's input stream, and read from its output stream. + /// + public abstract Stream InputStream { get; } + + /// + /// The server's output stream. + /// + /// + /// The connection will read from the server's output stream, and write to its input stream. + /// + public abstract Stream OutputStream { get; } + + /// + /// Start or connect to the server. + /// + public abstract Task Start(); + + /// + /// Stop or disconnect from the server. + /// + public abstract Task Stop(); + + /// + /// Raise the event. + /// + protected virtual void OnExited() + { + _exitedSubject.OnNext(System.Reactive.Unit.Default); + _exitedSubject.OnCompleted(); + } + } +} diff --git a/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs b/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs new file mode 100644 index 000000000..f590b1136 --- /dev/null +++ b/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs @@ -0,0 +1,144 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace PowerShellEditorServices.Test.E2E +{ + /// + /// A is a that launches its server as an external process and communicates with it over STDIN / STDOUT. + /// + public class StdioServerProcess : ServerProcess + { + /// + /// A that describes how to start the server. + /// + readonly ProcessStartInfo _serverStartInfo; + + /// + /// The current server process (if any). + /// + Process _serverProcess; + + /// + /// Create a new . + /// + /// + /// The factory for loggers used by the process and its components. + /// + /// + /// A that describes how to start the server. + /// + public StdioServerProcess(ILoggerFactory loggerFactory, ProcessStartInfo serverStartInfo) + : base(loggerFactory) + { + if (serverStartInfo == null) + { + throw new ArgumentNullException(nameof(serverStartInfo)); + } + + _serverStartInfo = serverStartInfo; + } + + /// + /// Dispose of resources being used by the launcher. + /// + /// + /// Explicit disposal? + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + Process serverProcess = Interlocked.Exchange(ref _serverProcess, null); + if (serverProcess != null) + { + if (!serverProcess.HasExited) + { + serverProcess.Kill(); + } + + serverProcess.Dispose(); + } + } + } + + /// + /// Is the server running? + /// + public override bool IsRunning => !ServerExitCompletion.Task.IsCompleted; + + /// + /// The server's input stream. + /// + public override Stream InputStream => _serverProcess?.StandardInput?.BaseStream; + + /// + /// The server's output stream. + /// + public override Stream OutputStream => _serverProcess?.StandardOutput?.BaseStream; + + /// + /// Start or connect to the server. + /// + public override Task Start() + { + ServerExitCompletion = new TaskCompletionSource(); + + _serverStartInfo.CreateNoWindow = true; + _serverStartInfo.UseShellExecute = false; + _serverStartInfo.RedirectStandardInput = true; + _serverStartInfo.RedirectStandardOutput = true; + + Process serverProcess = _serverProcess = new Process + { + StartInfo = _serverStartInfo, + EnableRaisingEvents = true + }; + serverProcess.Exited += ServerProcess_Exit; + + if (!serverProcess.Start()) + { + throw new InvalidOperationException("Failed to launch language server ."); + } + + ServerStartCompletion.TrySetResult(null); + + return Task.CompletedTask; + } + + /// + /// Stop or disconnect from the server. + /// + public override async Task Stop() + { + Process serverProcess = Interlocked.Exchange(ref _serverProcess, null); + if (serverProcess != null && !serverProcess.HasExited) + { + serverProcess.Kill(); + } + + await ServerExitCompletion.Task; + } + + /// + /// Called when the server process has exited. + /// + /// + /// The event sender. + /// + /// + /// The event arguments. + /// + void ServerProcess_Exit(object sender, EventArgs args) + { + Log.LogDebug("Server process has exited."); + + OnExited(); + ServerExitCompletion.TrySetResult(null); + ServerStartCompletion = new TaskCompletionSource(); + } + } +} diff --git a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs index b0eca7af9..4fee3ef36 100644 --- a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs +++ b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using OmniSharp.Extensions.LanguageServer.Client.Processes; using Xunit; namespace PowerShellEditorServices.Test.E2E @@ -86,7 +85,7 @@ public async Task InitializeAsync() _psesProcess = new StdioServerProcess(factory, processStartInfo); await _psesProcess.Start(); - await CustomInitializeAsync(factory, _psesProcess); + await CustomInitializeAsync(factory, _psesProcess.OutputStream, _psesProcess.InputStream).ConfigureAwait(false); } public virtual async Task DisposeAsync() @@ -96,7 +95,8 @@ public virtual async Task DisposeAsync() public abstract Task CustomInitializeAsync( ILoggerFactory factory, - StdioServerProcess process); + Stream inputStream, + Stream outputStream); private static string SingleQuoteEscape(string str) { diff --git a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs index 9cd3a786e..487a4672f 100644 --- a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs @@ -29,7 +29,7 @@ public class LanguageServiceTests : IDisposable { private readonly WorkspaceService workspace; private readonly SymbolsService symbolsService; - private readonly CompletionHandler completionHandler; + private readonly PsesCompletionHandler completionHandler; private readonly PowerShellContextService powerShellContext; private static readonly string s_baseSharedScriptPath = Path.Combine( @@ -47,12 +47,12 @@ public LanguageServiceTests() powerShellContext = PowerShellContextFactory.Create(logger); workspace = new WorkspaceService(NullLoggerFactory.Instance); symbolsService = new SymbolsService(NullLoggerFactory.Instance, powerShellContext, workspace, new ConfigurationService()); - completionHandler = new CompletionHandler(NullLoggerFactory.Instance, powerShellContext, workspace); + completionHandler = new PsesCompletionHandler(NullLoggerFactory.Instance, powerShellContext, workspace); } public void Dispose() { - this.powerShellContext.Dispose(); + this.powerShellContext.Close(); } [Trait("Category", "Completions")] diff --git a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs index 4f246d0df..b2d0c2ba5 100644 --- a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs +++ b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs @@ -6,6 +6,7 @@ using System; using System.IO; using Microsoft.PowerShell.EditorServices.Services.TextDocument; +using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using Xunit; @@ -19,7 +20,7 @@ public class TokenOperationsTests private FoldingReference[] GetRegions(string text) { ScriptFile scriptFile = new ScriptFile( // Use any absolute path. Even if it doesn't exist. - new Uri(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), + DocumentUri.FromFileSystemPath(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), text, Version.Parse("5.0")); diff --git a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj index ca3203b5c..8f84b1504 100644 --- a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj +++ b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj @@ -22,6 +22,7 @@ + diff --git a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs index 34a67e4f8..7e66bca54 100644 --- a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs +++ b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs @@ -35,7 +35,7 @@ public PowerShellContextTests() public void Dispose() { - this.powerShellContext.Dispose(); + this.powerShellContext.Close(); this.powerShellContext = null; } diff --git a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs index 6ab21d35f..bf8e991a6 100644 --- a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs +++ b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs @@ -3,11 +3,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.PowerShell.EditorServices.Services.TextDocument; -using Microsoft.PowerShell.EditorServices.Test.Shared; using System; using System.IO; using System.Linq; +using Microsoft.PowerShell.EditorServices.Services.TextDocument; +using Microsoft.PowerShell.EditorServices.Test.Shared; +using Microsoft.PowerShell.EditorServices.Utility; +using OmniSharp.Extensions.LanguageServer.Protocol; using Xunit; namespace PSLanguageService.Test @@ -191,7 +193,7 @@ public void FindsDotSourcedFiles() ScriptFile scriptFile = new ScriptFile( // Use any absolute path. Even if it doesn't exist. - new Uri(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), + DocumentUri.FromFileSystemPath(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), stringReader, PowerShellVersion); @@ -248,7 +250,7 @@ internal static ScriptFile CreateScriptFile(string initialString) ScriptFile fileToChange = new ScriptFile( // Use any absolute path. Even if it doesn't exist. - new Uri(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), + DocumentUri.FromFileSystemPath(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), stringReader, PowerShellVersion); @@ -576,8 +578,7 @@ public void PropertiesInitializedCorrectlyForFile() var path = Path.Combine(Path.GetTempPath(), "TestFile.ps1"); var scriptFile = ScriptFileChangeTests.CreateScriptFile(""); - Assert.Equal(path, scriptFile.FilePath); - Assert.Equal(path, scriptFile.ClientFilePath); + Assert.Equal(path, scriptFile.FilePath, ignoreCase: !VersionUtils.IsLinux); Assert.True(scriptFile.IsAnalysisEnabled); Assert.False(scriptFile.IsInMemory); Assert.Empty(scriptFile.ReferencedFiles); @@ -600,10 +601,9 @@ public void PropertiesInitializedCorrectlyForUntitled() using (StringReader stringReader = new StringReader(script)) { // Create an in-memory file from the StringReader - var scriptFile = new ScriptFile(new Uri(path), stringReader, PowerShellVersion); + var scriptFile = new ScriptFile(DocumentUri.From(path), stringReader, PowerShellVersion); Assert.Equal(path, scriptFile.FilePath); - Assert.Equal(path, scriptFile.ClientFilePath); Assert.Equal(path, scriptFile.DocumentUri); Assert.True(scriptFile.IsAnalysisEnabled); Assert.True(scriptFile.IsInMemory); @@ -625,16 +625,16 @@ public void DocumentUriRetunsCorrectStringForAbsolutePath() if (Environment.OSVersion.Platform == PlatformID.Win32NT) { path = @"C:\Users\AmosBurton\projects\Rocinate\ProtoMolecule.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///c:/Users/AmosBurton/projects/Rocinate/ProtoMolecule.ps1", scriptFile.DocumentUri); path = @"c:\Users\BobbieDraper\projects\Rocinate\foo's_~#-[@] +,;=%.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///c:/Users/BobbieDraper/projects/Rocinate/foo%27s_~%23-%5B%40%5D%20%2B%2C%3B%3D%25.ps1", scriptFile.DocumentUri); // Test UNC path path = @"\\ClarissaMao\projects\Rocinate\foo's_~#-[@] +,;=%.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); // UNC authorities are lowercased. This is what VS Code does as well. Assert.Equal("file://clarissamao/projects/Rocinate/foo%27s_~%23-%5B%40%5D%20%2B%2C%3B%3D%25.ps1", scriptFile.DocumentUri); } @@ -642,19 +642,19 @@ public void DocumentUriRetunsCorrectStringForAbsolutePath() { // Test the following only on Linux and macOS. path = "/home/AlexKamal/projects/Rocinate/ProtoMolecule.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///home/AlexKamal/projects/Rocinate/ProtoMolecule.ps1", scriptFile.DocumentUri); path = "/home/BobbieDraper/projects/Rocinate/foo's_~#-[@] +,;=%.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///home/BobbieDraper/projects/Rocinate/foo%27s_~%23-%5B%40%5D%20%2B%2C%3B%3D%25.ps1", scriptFile.DocumentUri); path = "/home/NaomiNagata/projects/Rocinate/Proto:Mole:cule.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///home/NaomiNagata/projects/Rocinate/Proto%3AMole%3Acule.ps1", scriptFile.DocumentUri); path = "/home/JamesHolden/projects/Rocinate/Proto:Mole\\cule.ps1"; - scriptFile = new ScriptFile(new Uri(path), emptyStringReader, PowerShellVersion); + scriptFile = new ScriptFile(DocumentUri.FromFileSystemPath(path), emptyStringReader, PowerShellVersion); Assert.Equal("file:///home/JamesHolden/projects/Rocinate/Proto%3AMole%5Ccule.ps1", scriptFile.DocumentUri); } }