diff --git a/src/PowerShellEditorServices/Server/PsesDebugServer.cs b/src/PowerShellEditorServices/Server/PsesDebugServer.cs index 89bdaeb3c..088812f7e 100644 --- a/src/PowerShellEditorServices/Server/PsesDebugServer.cs +++ b/src/PowerShellEditorServices/Server/PsesDebugServer.cs @@ -81,7 +81,11 @@ public async Task StartAsync() .WithHandler() .WithHandler() .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() .WithHandler() .WithHandler() diff --git a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs index 5b0522818..8612d595f 100644 --- a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs +++ b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs @@ -80,7 +80,6 @@ public async Task StartAsync() .WithOutput(_outputStream) .WithServices(serviceCollection => { - // NOTE: This adds a lot of services! serviceCollection.AddPsesLanguageServices(_hostDetails); }) @@ -94,7 +93,8 @@ public async Task StartAsync() .WithHandler() .WithHandler() .WithHandler() - .WithHandler() + .WithHandler() + .WithHandler() .WithHandler() .WithHandler() .WithHandler() diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DebuggerActionHandlers.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DebuggerActionHandlers.cs index 7da2909ff..2276aee75 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DebuggerActionHandlers.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DebuggerActionHandlers.cs @@ -4,59 +4,78 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; using Microsoft.PowerShell.EditorServices.Services; using OmniSharp.Extensions.DebugAdapter.Protocol.Requests; using OmniSharp.Extensions.JsonRpc; namespace Microsoft.PowerShell.EditorServices.Handlers { - // TODO: Inherit from ABCs instead of satisfying interfaces. - internal class DebuggerActionHandlers : IContinueHandler, INextHandler, IPauseHandler, IStepInHandler, IStepOutHandler + internal class ContinueHandler : ContinueHandlerBase { - private readonly ILogger _logger; private readonly DebugService _debugService; - public DebuggerActionHandlers( - ILoggerFactory loggerFactory, - DebugService debugService) - { - _logger = loggerFactory.CreateLogger(); - _debugService = debugService; - } + public ContinueHandler(DebugService debugService) => _debugService = debugService; - public Task Handle(ContinueArguments request, CancellationToken cancellationToken) + public override Task Handle(ContinueArguments request, CancellationToken cancellationToken) { _debugService.Continue(); return Task.FromResult(new ContinueResponse()); } + } + + internal class NextHandler : NextHandlerBase + { + private readonly DebugService _debugService; - public Task Handle(NextArguments request, CancellationToken cancellationToken) + public NextHandler(DebugService debugService) => _debugService = debugService; + + public override Task Handle(NextArguments request, CancellationToken cancellationToken) { _debugService.StepOver(); return Task.FromResult(new NextResponse()); } + } + + internal class PauseHandler : PauseHandlerBase + { + private readonly DebugService _debugService; - public Task Handle(PauseArguments request, CancellationToken cancellationToken) + public PauseHandler(DebugService debugService) => _debugService = debugService; + + public override Task Handle(PauseArguments request, CancellationToken cancellationToken) { try { _debugService.Break(); return Task.FromResult(new PauseResponse()); } - catch(NotSupportedException e) + catch (NotSupportedException e) { throw new RpcErrorException(0, e.Message); } } + } + + internal class StepInHandler : StepInHandlerBase + { + private readonly DebugService _debugService; + + public StepInHandler(DebugService debugService) => _debugService = debugService; - public Task Handle(StepInArguments request, CancellationToken cancellationToken) + public override Task Handle(StepInArguments request, CancellationToken cancellationToken) { _debugService.StepIn(); return Task.FromResult(new StepInResponse()); } + } + + internal class StepOutHandler : StepOutHandlerBase + { + private readonly DebugService _debugService; + + public StepOutHandler(DebugService debugService) => _debugService = debugService; - public Task Handle(StepOutArguments request, CancellationToken cancellationToken) + public override Task Handle(StepOutArguments request, CancellationToken cancellationToken) { _debugService.StepOut(); return Task.FromResult(new StepOutResponse()); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index bc3e0a746..50de27462 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -26,15 +26,12 @@ public PsesCodeActionHandler(ILoggerFactory factory, AnalysisService analysisSer _analysisService = analysisService; } - protected override CodeActionRegistrationOptions CreateRegistrationOptions(CodeActionCapability capability, ClientCapabilities clientCapabilities) + protected override CodeActionRegistrationOptions CreateRegistrationOptions(CodeActionCapability capability, ClientCapabilities clientCapabilities) => new() { - return new() - { - // TODO: What do we do with the arguments? - DocumentSelector = LspUtils.PowerShellDocumentSelector, - CodeActionKinds = new CodeActionKind[] { CodeActionKind.QuickFix } - }; - } + // TODO: What do we do with the arguments? + DocumentSelector = LspUtils.PowerShellDocumentSelector, + CodeActionKinds = new CodeActionKind[] { CodeActionKind.QuickFix } + }; // TODO: Either fix or ignore "method lacks 'await'" warning. public override async Task Handle(CodeAction request, CancellationToken cancellationToken) diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs index a6a7c6dd7..108dace6c 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs @@ -19,70 +19,46 @@ namespace Microsoft.PowerShell.EditorServices.Handlers { - // TODO: Use ABCs. - internal class PsesCodeLensHandlers : ICodeLensHandler, ICodeLensResolveHandler + internal class PsesCodeLensHandlers : CodeLensHandlerBase { private readonly ILogger _logger; private readonly SymbolsService _symbolsService; private readonly WorkspaceService _workspaceService; - private CodeLensCapability _capability; - private readonly Guid _id = Guid.NewGuid(); - Guid ICanBeIdentifiedHandler.Id => _id; - public PsesCodeLensHandlers(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService, ConfigurationService configurationService) + public PsesCodeLensHandlers(ILoggerFactory factory, SymbolsService symbolsService, WorkspaceService workspaceService) { _logger = factory.CreateLogger(); _workspaceService = workspaceService; _symbolsService = symbolsService; } - public CodeLensRegistrationOptions GetRegistrationOptions(CodeLensCapability capability, ClientCapabilities clientCapabilities) => new CodeLensRegistrationOptions + protected override CodeLensRegistrationOptions CreateRegistrationOptions(CodeLensCapability capability, ClientCapabilities clientCapabilities) => new() { DocumentSelector = LspUtils.PowerShellDocumentSelector, ResolveProvider = true }; - public void SetCapability(CodeLensCapability capability, ClientCapabilities clientCapabilities) - { - _capability = capability; - } - - public Task Handle(CodeLensParams request, CancellationToken cancellationToken) + public override Task Handle(CodeLensParams request, CancellationToken cancellationToken) { ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); - CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile); - return Task.FromResult(new CodeLensContainer(codeLensResults)); } - public bool CanResolve(CodeLens value) - { - CodeLensData codeLensData = value.Data.ToObject(); - return value?.Data != null && _symbolsService.GetCodeLensProviders().Any(provider => provider.ProviderId.Equals(codeLensData.ProviderId)); - } - - public Task Handle(CodeLens request, CancellationToken cancellationToken) + public override Task Handle(CodeLens request, CancellationToken cancellationToken) { // TODO: Catch deserializtion exception on bad object CodeLensData codeLensData = request.Data.ToObject(); ICodeLensProvider originalProvider = _symbolsService .GetCodeLensProviders() - .FirstOrDefault(provider => provider.ProviderId.Equals(codeLensData.ProviderId)); + .FirstOrDefault(provider => provider.ProviderId.Equals(codeLensData.ProviderId, StringComparison.Ordinal)); - ScriptFile scriptFile = - _workspaceService.GetFile( - codeLensData.Uri); + ScriptFile scriptFile = _workspaceService.GetFile(codeLensData.Uri); return originalProvider.ResolveCodeLens(request, scriptFile); } - public void SetCapability(CodeLensCapability capability) - { - _capability = capability; - } - /// /// Get all the CodeLenses for a given script file. /// @@ -104,30 +80,23 @@ private CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) /// An IEnumerable containing the results of all providers /// that were invoked successfully. /// - private IEnumerable InvokeProviders( - Func invokeFunc) + private IEnumerable InvokeProviders(Func invokeFunc) { - Stopwatch invokeTimer = new Stopwatch(); - List providerResults = new List(); + Stopwatch invokeTimer = new(); + List providerResults = new(); foreach (ICodeLensProvider provider in _symbolsService.GetCodeLensProviders()) { try { invokeTimer.Restart(); - providerResults.Add(invokeFunc(provider)); - invokeTimer.Stop(); - - this._logger.LogTrace( - $"Invocation of provider '{provider.GetType().Name}' completed in {invokeTimer.ElapsedMilliseconds}ms."); + _logger.LogTrace($"Invocation of provider '{provider.GetType().Name}' completed in {invokeTimer.ElapsedMilliseconds}ms."); } catch (Exception e) { - this._logger.LogException( - $"Exception caught while invoking provider {provider.GetType().Name}:", - e); + _logger.LogException($"Exception caught while invoking provider {provider.GetType().Name}:", e); } } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs index bd3a45713..288d14774 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs @@ -22,17 +22,12 @@ namespace Microsoft.PowerShell.EditorServices.Handlers { - // TODO: Use ABCs. - internal class PsesCompletionHandler : ICompletionHandler, ICompletionResolveHandler + internal class PsesCompletionHandler : CompletionHandlerBase { private readonly ILogger _logger; private readonly IRunspaceContext _runspaceContext; private readonly IInternalPowerShellExecutionService _executionService; private readonly WorkspaceService _workspaceService; - private CompletionCapability _capability; - private readonly Guid _id = Guid.NewGuid(); - - Guid ICanBeIdentifiedHandler.Id => _id; public PsesCompletionHandler( ILoggerFactory factory, @@ -46,14 +41,15 @@ public PsesCompletionHandler( _workspaceService = workspaceService; } - public CompletionRegistrationOptions GetRegistrationOptions(CompletionCapability capability, ClientCapabilities clientCapabilities) => new() + protected override CompletionRegistrationOptions CreateRegistrationOptions(CompletionCapability capability, ClientCapabilities clientCapabilities) => new() { + // TODO: What do we do with the arguments? DocumentSelector = LspUtils.PowerShellDocumentSelector, ResolveProvider = true, TriggerCharacters = new[] { ".", "-", ":", "\\", "$" } }; - public async Task Handle(CompletionParams request, CancellationToken cancellationToken) + public override async Task Handle(CompletionParams request, CancellationToken cancellationToken) { int cursorLine = request.Position.Line + 1; int cursorColumn = request.Position.Character + 1; @@ -68,13 +64,8 @@ public async Task Handle(CompletionParams request, CancellationT return new CompletionList(completionResults); } - public static bool CanResolve(CompletionItem value) - { - return value.Kind == CompletionItemKind.Function; - } - // Handler for "completionItem/resolve". In VSCode this is fired when a completion item is highlighted in the completion list. - public async Task Handle(CompletionItem request, CancellationToken cancellationToken) + public override async Task Handle(CompletionItem request, CancellationToken cancellationToken) { // We currently only support this request for anything that returns a CommandInfo: // functions, cmdlets, aliases. No detail means the module hasn't been imported yet and @@ -105,11 +96,6 @@ public async Task Handle(CompletionItem request, CancellationTok return request; } - public void SetCapability(CompletionCapability capability, ClientCapabilities clientCapabilities) - { - _capability = capability; - } - /// /// Gets completions for a statement contained in the given /// script file at the specified line and column position. @@ -126,7 +112,7 @@ public void SetCapability(CompletionCapability capability, ClientCapabilities cl /// /// A CommandCompletion instance completions for the identified statement. /// - public async Task> GetCompletionsInFileAsync( + internal async Task> GetCompletionsInFileAsync( ScriptFile scriptFile, int lineNumber, int columnNumber, @@ -142,15 +128,15 @@ public async Task> GetCompletionsInFileAsync( _logger, cancellationToken).ConfigureAwait(false); - // Only calculate the replacement range if there are completions. - BufferRange replacedRange = new(0, 0, 0, 0); - if (result.CompletionMatches.Count > 0) + if (result.CompletionMatches.Count == 0) { - replacedRange = scriptFile.GetRangeBetweenOffsets( - result.ReplacementIndex, - result.ReplacementIndex + result.ReplacementLength); + return Array.Empty(); } + BufferRange replacedRange = scriptFile.GetRangeBetweenOffsets( + result.ReplacementIndex, + result.ReplacementIndex + result.ReplacementLength); + // Create OmniSharp CompletionItems from PowerShell CompletionResults. We use a for loop // because the index is used for sorting. CompletionItem[] completionItems = new CompletionItem[result.CompletionMatches.Count]; @@ -282,8 +268,8 @@ private static bool TryBuildSnippet(string completionText, out string snippet) // Since we want to use a "tab stop" we need to escape a few things. StringBuilder sb = new StringBuilder(completionText) .Replace(@"\", @"\\") - .Replace(@"}", @"\}") - .Replace(@"$", @"\$"); + .Replace("}", @"\}") + .Replace("$", @"\$"); snippet = sb.Insert(sb.Length - 1, "$0").ToString(); return true; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs index c62c9f5db..0ddeedacd 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs @@ -13,54 +13,44 @@ namespace Microsoft.PowerShell.EditorServices.Handlers { // TODO: Add IDocumentOnTypeFormatHandler to support on-type formatting. - // TODO: Use ABCs. - internal class PsesDocumentFormattingHandlers : IDocumentFormattingHandler, IDocumentRangeFormattingHandler + internal class PsesDocumentFormattingHandler : DocumentFormattingHandlerBase { private readonly ILogger _logger; private readonly AnalysisService _analysisService; private readonly ConfigurationService _configurationService; private readonly WorkspaceService _workspaceService; - private DocumentFormattingCapability _documentFormattingCapability; - private DocumentRangeFormattingCapability _documentRangeFormattingCapability; - - public PsesDocumentFormattingHandlers( + public PsesDocumentFormattingHandler( ILoggerFactory factory, AnalysisService analysisService, ConfigurationService configurationService, WorkspaceService workspaceService) { - _logger = factory.CreateLogger(); + _logger = factory.CreateLogger(); _analysisService = analysisService; _configurationService = configurationService; _workspaceService = workspaceService; } - public DocumentFormattingRegistrationOptions GetRegistrationOptions(DocumentFormattingCapability capability, ClientCapabilities clientCapabilities) => new DocumentFormattingRegistrationOptions - { - DocumentSelector = LspUtils.PowerShellDocumentSelector - }; - - public DocumentRangeFormattingRegistrationOptions GetRegistrationOptions(DocumentRangeFormattingCapability capability, ClientCapabilities clientCapabilities) => new DocumentRangeFormattingRegistrationOptions + protected override DocumentFormattingRegistrationOptions CreateRegistrationOptions(DocumentFormattingCapability capability, ClientCapabilities clientCapabilities) => new() { DocumentSelector = LspUtils.PowerShellDocumentSelector }; - public async Task Handle(DocumentFormattingParams request, CancellationToken cancellationToken) + public override async Task Handle(DocumentFormattingParams request, CancellationToken cancellationToken) { - var scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); - var pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable( - (int)request.Options.TabSize, + Services.TextDocument.ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); + System.Collections.Hashtable pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable( + request.Options.TabSize, request.Options.InsertSpaces, _logger); - - // TODO raise an error event in case format returns null + // TODO: Raise an error event in case format returns null. string formattedScript; Range editRange; - var extent = scriptFile.ScriptAst.Extent; + System.Management.Automation.Language.IScriptExtent extent = scriptFile.ScriptAst.Extent; - // todo create an extension for converting range to script extent + // TODO: Create an extension for converting range to script extent. editRange = new Range { Start = new Position @@ -79,7 +69,12 @@ public async Task Handle(DocumentFormattingParams request, Ca scriptFile.Contents, pssaSettings, null).ConfigureAwait(false); - formattedScript = formattedScript ?? scriptFile.Contents; + + if (formattedScript is null) + { + _logger.LogWarning($"Formatting returned null. Returning original contents for file: {scriptFile.DocumentUri}"); + formattedScript = scriptFile.Contents; + } return new TextEditContainer(new TextEdit { @@ -87,21 +82,46 @@ public async Task Handle(DocumentFormattingParams request, Ca Range = editRange }); } + } - public async Task Handle(DocumentRangeFormattingParams request, CancellationToken cancellationToken) + internal class PsesDocumentRangeFormattingHandler : DocumentRangeFormattingHandlerBase + { + private readonly ILogger _logger; + private readonly AnalysisService _analysisService; + private readonly ConfigurationService _configurationService; + private readonly WorkspaceService _workspaceService; + + public PsesDocumentRangeFormattingHandler( + ILoggerFactory factory, + AnalysisService analysisService, + ConfigurationService configurationService, + WorkspaceService workspaceService) + { + _logger = factory.CreateLogger(); + _analysisService = analysisService; + _configurationService = configurationService; + _workspaceService = workspaceService; + } + + protected override DocumentRangeFormattingRegistrationOptions CreateRegistrationOptions(DocumentRangeFormattingCapability capability, ClientCapabilities clientCapabilities) => new() + { + DocumentSelector = LspUtils.PowerShellDocumentSelector + }; + + public override async Task Handle(DocumentRangeFormattingParams request, CancellationToken cancellationToken) { - var scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); - var pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable( - (int)request.Options.TabSize, + Services.TextDocument.ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); + System.Collections.Hashtable pssaSettings = _configurationService.CurrentSettings.CodeFormatting.GetPSSASettingsHashtable( + request.Options.TabSize, request.Options.InsertSpaces, _logger); - // TODO raise an error event in case format returns null; + // TODO: Raise an error event in case format returns null. string formattedScript; Range editRange; - var extent = scriptFile.ScriptAst.Extent; + System.Management.Automation.Language.IScriptExtent extent = scriptFile.ScriptAst.Extent; - // TODO create an extension for converting range to script extent + // TODO: Create an extension for converting range to script extent. editRange = new Range { Start = new Position @@ -117,7 +137,7 @@ public async Task Handle(DocumentRangeFormattingParams reques }; Range range = request.Range; - var rangeList = range == null ? null : new int[] + int[] rangeList = range == null ? null : new int[] { range.Start.Line + 1, range.Start.Character + 1, @@ -130,9 +150,9 @@ public async Task Handle(DocumentRangeFormattingParams reques pssaSettings, rangeList).ConfigureAwait(false); - if (formattedScript == null) + if (formattedScript is null) { - _logger.LogWarning("Formatting returned null. Returning original contents for file: {0}", scriptFile.DocumentUri); + _logger.LogWarning($"Formatting returned null. Returning original contents for file: {scriptFile.DocumentUri}"); formattedScript = scriptFile.Contents; } @@ -142,15 +162,5 @@ public async Task Handle(DocumentRangeFormattingParams reques Range = editRange }); } - - public void SetCapability(DocumentFormattingCapability capability) - { - _documentFormattingCapability = capability; - } - - public void SetCapability(DocumentRangeFormattingCapability capability) - { - _documentRangeFormattingCapability = capability; - } } }