From da943fe2d59829414df3d3bd2f5c0d3f57394492 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 7 Jun 2017 15:48:30 -0700 Subject: [PATCH 1/5] Add IComponentRegistry dependency container interface This change adds a new interface called IComponentRegistry which acts as a dependency container for components in PowerShell Editor Services. It also adds a default ComponentRegistry class which implements this interface so that it can be used in the server. --- .../Components/ComponentRegistry.cs | 80 +++++++++++++++++++ .../Components/IComponentRegistry.cs | 55 +++++++++++++ .../Session/EditorSession.cs | 6 ++ 3 files changed, 141 insertions(+) create mode 100644 src/PowerShellEditorServices/Components/ComponentRegistry.cs create mode 100644 src/PowerShellEditorServices/Components/IComponentRegistry.cs diff --git a/src/PowerShellEditorServices/Components/ComponentRegistry.cs b/src/PowerShellEditorServices/Components/ComponentRegistry.cs new file mode 100644 index 000000000..48a794174 --- /dev/null +++ b/src/PowerShellEditorServices/Components/ComponentRegistry.cs @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.EditorServices.Components +{ + /// + /// Provides a default implementation for the IComponentRegistry + /// interface. + /// + public class ComponentRegistry : IComponentRegistry + { + private Dictionary componentRegistry = + new Dictionary(); + + /// + /// Registers an instance of the specified component type + /// or throws an ArgumentException if an instance has + /// already been registered. + /// + /// + /// The instance of the component to be registered. + /// + /// + /// The provided component instance for convenience in assignment + /// statements. + /// + public TComponent Register(TComponent componentInstance) + where TComponent : class + { + this.componentRegistry.Add(typeof(TComponent), componentInstance); + return componentInstance; + } + + + /// + /// Gets the registered instance of the specified + /// component type or throws a KeyNotFoundException if + /// no instance has been registered. + /// + /// The implementation of the specified type. + public TComponent Get() + where TComponent : class + { + return (TComponent)this.componentRegistry[typeof(TComponent)]; + } + + /// + /// Attempts to retrieve the instance of the specified + /// component type and, if found, stores it in the + /// componentInstance parameter. + /// + /// + /// The out parameter in which the found instance will be stored. + /// + /// + /// True if a registered instance was found, false otherwise. + /// + public bool TryGet(out TComponent componentInstance) + where TComponent : class + { + object componentObject = null; + componentInstance = null; + + if (this.componentRegistry.TryGetValue(typeof(TComponent), out componentObject)) + { + componentInstance = componentObject as TComponent; + return componentInstance != null; + } + + return false; + } + } +} diff --git a/src/PowerShellEditorServices/Components/IComponentRegistry.cs b/src/PowerShellEditorServices/Components/IComponentRegistry.cs new file mode 100644 index 000000000..c2f813b29 --- /dev/null +++ b/src/PowerShellEditorServices/Components/IComponentRegistry.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.EditorServices.Components +{ + /// + /// Specifies the contract for a registry of component interfaces. + /// + public interface IComponentRegistry + { + /// + /// Registers an instance of the specified component type + /// or throws an ArgumentException if an instance has + /// already been registered. + /// + /// + /// The instance of the component to be registered. + /// + /// + /// The provided component instance for convenience in assignment + /// statements. + /// + TComponent Register(TComponent componentInstance) + where TComponent : class; + + /// + /// Gets the registered instance of the specified + /// component type or throws a KeyNotFoundException if + /// no instance has been registered. + /// + /// The implementation of the specified type. + TComponent Get() + where TComponent : class; + + /// + /// Attempts to retrieve the instance of the specified + /// component type and, if found, stores it in the + /// componentInstance parameter. + /// + /// + /// The out parameter in which the found instance will be stored. + /// + /// + /// True if a registered instance was found, false otherwise. + /// + bool TryGet(out TComponent componentInstance) + where TComponent : class; + } +} \ No newline at end of file diff --git a/src/PowerShellEditorServices/Session/EditorSession.cs b/src/PowerShellEditorServices/Session/EditorSession.cs index 6c00581b4..36b6db062 100644 --- a/src/PowerShellEditorServices/Session/EditorSession.cs +++ b/src/PowerShellEditorServices/Session/EditorSession.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using Microsoft.PowerShell.EditorServices.Components; using Microsoft.PowerShell.EditorServices.Console; using Microsoft.PowerShell.EditorServices.Extensions; using Microsoft.PowerShell.EditorServices.Session; @@ -71,6 +72,11 @@ public class EditorSession /// public RemoteFileManager RemoteFileManager { get; private set; } + /// + /// Gets the IComponentCollection instance for this session. + /// + public IComponentRegistry Components { get; } = new ComponentRegistry(); + #endregion #region Constructors From 371c0ae05066400d7a010900bccb5d1c46261ad6 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 7 Jun 2017 15:52:31 -0700 Subject: [PATCH 2/5] Add IProvider and IProviderCollection interfaces and implementations This change introduces a new provider model into PowerShell Editor Services so that feature components can have an arbitrary number of providers registered which are used in addition to any default implementations. This is intended to be used as an extensibility mechanism. --- .../Providers/IProvider.cs | 19 ++++++++ .../Providers/IProviderCollection.cs | 22 +++++++++ .../Providers/ProviderBase.cs | 19 ++++++++ .../Providers/ProviderCollection.cs | 46 +++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/PowerShellEditorServices/Providers/IProvider.cs create mode 100644 src/PowerShellEditorServices/Providers/IProviderCollection.cs create mode 100644 src/PowerShellEditorServices/Providers/ProviderBase.cs create mode 100644 src/PowerShellEditorServices/Providers/ProviderCollection.cs diff --git a/src/PowerShellEditorServices/Providers/IProvider.cs b/src/PowerShellEditorServices/Providers/IProvider.cs new file mode 100644 index 000000000..fc12c9323 --- /dev/null +++ b/src/PowerShellEditorServices/Providers/IProvider.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.PowerShell.EditorServices +{ + /// + /// Defines the contract for a feature provider, particularly for provider identification. + /// + public interface IProvider + { + /// + /// Specifies a unique identifier for a provider, typically a + /// fully-qualified name like "Microsoft.PowerShell.EditorServices.MyProvider" + /// + string ProviderId { get; } + } +} diff --git a/src/PowerShellEditorServices/Providers/IProviderCollection.cs b/src/PowerShellEditorServices/Providers/IProviderCollection.cs new file mode 100644 index 000000000..5099c4699 --- /dev/null +++ b/src/PowerShellEditorServices/Providers/IProviderCollection.cs @@ -0,0 +1,22 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.PowerShell.EditorServices +{ + /// + /// Defines the contract for a collection of provider implementations. + /// + public interface IProviderCollection : IEnumerable + where TProvider : IProvider + { + /// + /// Adds a provider to the collection. + /// + /// The provider to be added. + void Add(TProvider provider); + } +} diff --git a/src/PowerShellEditorServices/Providers/ProviderBase.cs b/src/PowerShellEditorServices/Providers/ProviderBase.cs new file mode 100644 index 000000000..35fa94335 --- /dev/null +++ b/src/PowerShellEditorServices/Providers/ProviderBase.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.PowerShell.EditorServices +{ + /// + /// Provides a base implementation of IProvider. + /// + public abstract class ProviderBase : IProvider + { + /// + /// Gets the provider class type's FullName as the + /// ProviderId. + /// + public string ProviderId => this.GetType().FullName; + } +} diff --git a/src/PowerShellEditorServices/Providers/ProviderCollection.cs b/src/PowerShellEditorServices/Providers/ProviderCollection.cs new file mode 100644 index 000000000..272ceab5c --- /dev/null +++ b/src/PowerShellEditorServices/Providers/ProviderCollection.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.PowerShell.EditorServices +{ + /// + /// Provides a default implementation of IProviderCollection. + /// + public class ProviderCollection : IProviderCollection + where TProvider : IProvider + { + #region Private Fields + + private List providerList = new List(); + + #endregion + + #region IProviderCollection Implementation + + void IProviderCollection.Add(TProvider provider) + { + if (!this.providerList.Contains(provider)) + { + this.providerList.Add(provider); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.providerList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.providerList.GetEnumerator(); + } + + #endregion + } +} \ No newline at end of file From dcc620f369415505b3276623e0293f6fc5a3188e Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 7 Jun 2017 17:46:21 -0700 Subject: [PATCH 3/5] Add IDocumentSymbols and IDocumentSymbolProvider interfaces and impls This change adds the IDocumentSymbols and IDocumentSymbolProvider interfaces plus their implementations, moving the existing symbol provider classes over to this new model. --- .../EditorServicesHost.cs | 9 ++ .../Symbols/DocumentSymbolFeature.cs | 114 ++++++++++++++++++ .../Server/LanguageServer.cs | 9 +- .../Language/DocumentSymbolProvider.cs | 23 ---- .../Language/LanguageService.cs | 11 +- .../Language/PSDDocumentSymbolProvider.cs | 21 ---- .../Language/PesterDocumentSymbolProvider.cs | 39 ------ .../Language/ScriptDocumentSymbolProvider.cs | 26 ---- .../Symbols/IDocumentSymbolProvider.cs | 24 ++++ .../Symbols/IDocumentSymbols.cs | 31 +++++ .../Symbols/PesterDocumentSymbolProvider.cs | 51 ++++++++ .../Symbols/PsdDocumentSymbolProvider.cs | 33 +++++ .../Symbols/ScriptDocumentSymbolProvider.cs | 47 ++++++++ 13 files changed, 319 insertions(+), 119 deletions(-) create mode 100644 src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs delete mode 100644 src/PowerShellEditorServices/Language/DocumentSymbolProvider.cs delete mode 100644 src/PowerShellEditorServices/Language/PSDDocumentSymbolProvider.cs delete mode 100644 src/PowerShellEditorServices/Language/PesterDocumentSymbolProvider.cs delete mode 100644 src/PowerShellEditorServices/Language/ScriptDocumentSymbolProvider.cs create mode 100644 src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs create mode 100644 src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs create mode 100644 src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs create mode 100644 src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs create mode 100644 src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs diff --git a/src/PowerShellEditorServices.Host/EditorServicesHost.cs b/src/PowerShellEditorServices.Host/EditorServicesHost.cs index 182166732..fc1ea00c9 100644 --- a/src/PowerShellEditorServices.Host/EditorServicesHost.cs +++ b/src/PowerShellEditorServices.Host/EditorServicesHost.cs @@ -8,6 +8,7 @@ using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel; using Microsoft.PowerShell.EditorServices.Protocol.Server; using Microsoft.PowerShell.EditorServices.Session; +using Microsoft.PowerShell.EditorServices.Symbols; using Microsoft.PowerShell.EditorServices.Utility; using System; using System.Collections.Generic; @@ -346,6 +347,14 @@ private EditorSession CreateSession( editorSession.StartSession(powerShellContext, hostUserInterface); + // TODO: Move component registrations elsewhere! + editorSession.Components.Register(this.logger); + editorSession.Components.Register(messageHandlers); + editorSession.Components.Register(messageSender); + editorSession.Components.Register(powerShellContext); + + DocumentSymbolFeature.Create(editorSession.Components, editorSession); + return editorSession; } diff --git a/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs b/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs new file mode 100644 index 000000000..27f72af83 --- /dev/null +++ b/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs @@ -0,0 +1,114 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Components; +using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; +using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; +using Microsoft.PowerShell.EditorServices.Utility; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +using Servers = Microsoft.PowerShell.EditorServices.Protocol.Server; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + internal class DocumentSymbolFeature : IDocumentSymbols + { + private EditorSession editorSession; + + public IProviderCollection Providers { get; } = + new ProviderCollection(); + + public DocumentSymbolFeature( + EditorSession editorSession, + IMessageHandlers messageHandlers, + ILogger logger) + { + this.editorSession = editorSession; + + messageHandlers.SetRequestHandler( + DocumentSymbolRequest.Type, + this.HandleDocumentSymbolRequest); + } + + public static DocumentSymbolFeature Create( + IComponentRegistry components, + EditorSession editorSession) + { + var documentSymbols = + new DocumentSymbolFeature( + editorSession, + components.Get(), + components.Get()); + + documentSymbols.Providers.Add( + new ScriptDocumentSymbolProvider( + editorSession.PowerShellContext.LocalPowerShellVersion.Version)); + + documentSymbols.Providers.Add( + new PsdDocumentSymbolProvider()); + + documentSymbols.Providers.Add( + new PesterDocumentSymbolProvider()); + + editorSession.Components.Register(documentSymbols); + + return documentSymbols; + } + + public IEnumerable ProvideDocumentSymbols(ScriptFile scriptFile) + { + throw new NotImplementedException(); + } + + protected async Task HandleDocumentSymbolRequest( + DocumentSymbolParams documentSymbolParams, + RequestContext requestContext) + { + ScriptFile scriptFile = + editorSession.Workspace.GetFile( + documentSymbolParams.TextDocument.Uri); + + IEnumerable foundSymbols = + this.Providers + .SelectMany( + provider => provider.ProvideDocumentSymbols(scriptFile)); + + SymbolInformation[] symbols = null; + + string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath); + + if (foundSymbols != null) + { + symbols = + foundSymbols + .Select(r => + { + return new SymbolInformation + { + ContainerName = containerName, + Kind = Servers.LanguageServer.GetSymbolKind(r.SymbolType), + Location = new Location + { + Uri = Servers.LanguageServer.GetFileUri(r.FilePath), + Range = Servers.LanguageServer.GetRangeFromScriptRegion(r.ScriptRegion) + }, + Name = Servers.LanguageServer.GetDecoratedSymbolName(r) + }; + }) + .ToArray(); + } + else + { + symbols = new SymbolInformation[0]; + } + + await requestContext.SendResult(symbols); + } + } +} diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 978a9c080..8f056f255 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -100,7 +100,6 @@ public void Start() this.messageHandlers.SetRequestHandler(SignatureHelpRequest.Type, this.HandleSignatureHelpRequest); this.messageHandlers.SetRequestHandler(DocumentHighlightRequest.Type, this.HandleDocumentHighlightRequest); this.messageHandlers.SetRequestHandler(HoverRequest.Type, this.HandleHoverRequest); - this.messageHandlers.SetRequestHandler(DocumentSymbolRequest.Type, this.HandleDocumentSymbolRequest); this.messageHandlers.SetRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest); this.messageHandlers.SetRequestHandler(CodeActionRequest.Type, this.HandleCodeActionRequest); @@ -945,7 +944,7 @@ protected async Task HandleDocumentSymbolRequest( await requestContext.SendResult(symbols); } - private SymbolKind GetSymbolKind(SymbolType symbolType) + public static SymbolKind GetSymbolKind(SymbolType symbolType) { switch (symbolType) { @@ -959,7 +958,7 @@ private SymbolKind GetSymbolKind(SymbolType symbolType) } } - private string GetDecoratedSymbolName(SymbolReference symbolReference) + public static string GetDecoratedSymbolName(SymbolReference symbolReference) { string name = symbolReference.SymbolName; @@ -1206,7 +1205,7 @@ await this.messageSender.SendEvent( #region Helper Methods - private static string GetFileUri(string filePath) + public static string GetFileUri(string filePath) { // If the file isn't untitled, return a URI-style path return @@ -1215,7 +1214,7 @@ private static string GetFileUri(string filePath) : filePath; } - private static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion) + public static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion) { return new Range { diff --git a/src/PowerShellEditorServices/Language/DocumentSymbolProvider.cs b/src/PowerShellEditorServices/Language/DocumentSymbolProvider.cs deleted file mode 100644 index a418cae1d..000000000 --- a/src/PowerShellEditorServices/Language/DocumentSymbolProvider.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.PowerShell.EditorServices -{ - internal abstract class DocumentSymbolProvider - { - public IEnumerable GetSymbols(ScriptFile scriptFile, Version psVersion = null) - { - if (CanProvideFor(scriptFile)) - { - return GetSymbolsImpl(scriptFile, psVersion); - } - - return Enumerable.Empty(); - } - - protected abstract IEnumerable GetSymbolsImpl(ScriptFile scriptFile, Version psVersion); - - protected abstract bool CanProvideFor(ScriptFile scriptFile); - } -} diff --git a/src/PowerShellEditorServices/Language/LanguageService.cs b/src/PowerShellEditorServices/Language/LanguageService.cs index 366e7efe1..0dffd271e 100644 --- a/src/PowerShellEditorServices/Language/LanguageService.cs +++ b/src/PowerShellEditorServices/Language/LanguageService.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using Microsoft.PowerShell.EditorServices.Symbols; using Microsoft.PowerShell.EditorServices.Utility; using System; using System.Collections; @@ -33,7 +34,7 @@ public class LanguageService private string mostRecentRequestFile; private Dictionary> CmdletToAliasDictionary; private Dictionary AliasToCmdletDictionary; - private DocumentSymbolProvider[] documentSymbolProviders; + private IDocumentSymbolProvider[] documentSymbolProviders; const int DefaultWaitTimeoutMilliseconds = 5000; @@ -60,10 +61,10 @@ public LanguageService( this.CmdletToAliasDictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); this.AliasToCmdletDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); - this.documentSymbolProviders = new DocumentSymbolProvider[] + this.documentSymbolProviders = new IDocumentSymbolProvider[] { - new ScriptDocumentSymbolProvider(), - new PSDDocumentSymbolProvider(), + new ScriptDocumentSymbolProvider(powerShellContext.LocalPowerShellVersion.Version), + new PsdDocumentSymbolProvider(), new PesterDocumentSymbolProvider() }; } @@ -242,7 +243,7 @@ public FindOccurrencesResult FindSymbolsInFile(ScriptFile scriptFile) return new FindOccurrencesResult { FoundOccurrences = documentSymbolProviders - .SelectMany(p => p.GetSymbols(scriptFile, powerShellContext.LocalPowerShellVersion.Version)) + .SelectMany(p => p.ProvideDocumentSymbols(scriptFile)) .Select(reference => { reference.SourceLine = diff --git a/src/PowerShellEditorServices/Language/PSDDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Language/PSDDocumentSymbolProvider.cs deleted file mode 100644 index 85abd5bd7..000000000 --- a/src/PowerShellEditorServices/Language/PSDDocumentSymbolProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Microsoft.PowerShell.EditorServices -{ - internal class PSDDocumentSymbolProvider : DocumentSymbolProvider - { - protected override bool CanProvideFor(ScriptFile scriptFile) - { - return (scriptFile.FilePath != null && - scriptFile.FilePath.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) || - AstOperations.IsPowerShellDataFileAst(scriptFile.ScriptAst); - } - protected override IEnumerable GetSymbolsImpl(ScriptFile scriptFile, Version psVersion) - { - var findHashtableSymbolsVisitor = new FindHashtableSymbolsVisitor(); - scriptFile.ScriptAst.Visit(findHashtableSymbolsVisitor); - return findHashtableSymbolsVisitor.SymbolReferences; - } - } -} diff --git a/src/PowerShellEditorServices/Language/PesterDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Language/PesterDocumentSymbolProvider.cs deleted file mode 100644 index 4fb061700..000000000 --- a/src/PowerShellEditorServices/Language/PesterDocumentSymbolProvider.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Management.Automation.Language; - -namespace Microsoft.PowerShell.EditorServices -{ - internal class PesterDocumentSymbolProvider : DocumentSymbolProvider - { - protected override bool CanProvideFor(ScriptFile scriptFile) - { - return scriptFile.FilePath.EndsWith("tests.ps1", StringComparison.OrdinalIgnoreCase); - } - - protected override IEnumerable GetSymbolsImpl(ScriptFile scriptFile, Version psVersion) - { - var commandAsts = scriptFile.ScriptAst.FindAll(ast => - { - switch ((ast as CommandAst)?.GetCommandName().ToLower()) - { - case "describe": - case "context": - case "it": - return true; - - default: - return false; - } - }, - true); - - return commandAsts.Select(ast => new SymbolReference( - SymbolType.Function, - ast.Extent, - scriptFile.FilePath, - scriptFile.GetLine(ast.Extent.StartLineNumber))); - } - } -} diff --git a/src/PowerShellEditorServices/Language/ScriptDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Language/ScriptDocumentSymbolProvider.cs deleted file mode 100644 index 74aefa91d..000000000 --- a/src/PowerShellEditorServices/Language/ScriptDocumentSymbolProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Microsoft.PowerShell.EditorServices -{ - internal class ScriptDocumentSymbolProvider : DocumentSymbolProvider - { - protected override bool CanProvideFor(ScriptFile scriptFile) - { - return scriptFile != null && - scriptFile.FilePath != null && - (scriptFile.FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase) || - scriptFile.FilePath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase)); - } - - protected override IEnumerable GetSymbolsImpl( - ScriptFile scriptFile, - Version psVersion) - { - return AstOperations.FindSymbolsInDocument( - scriptFile.ScriptAst, - psVersion); - - } - } -} diff --git a/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs new file mode 100644 index 000000000..171bcd3b7 --- /dev/null +++ b/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + /// + /// Specifies the contract for a document symbols provider. + /// + public interface IDocumentSymbolProvider : IProvider + { + /// + /// Provides a list of symbols for the given document. + /// + /// + /// The document for which SymbolReferences should be provided. + /// + /// An IEnumerable collection of SymbolReferences. + IEnumerable ProvideDocumentSymbols(ScriptFile scriptFile); + } +} diff --git a/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs b/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs new file mode 100644 index 000000000..3529666e5 --- /dev/null +++ b/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + /// + /// Specifies the contract for an implementation of + /// the IDocumentSymbols component. + /// + public interface IDocumentSymbols + { + /// + /// Gets the collection of IDocumentSymbolsProvider implementations + /// that are registered with this component. + /// + IProviderCollection Providers { get; } + + /// + /// Provides a list of symbols for the given document. + /// + /// + /// The document for which SymbolReferences should be provided. + /// + /// An IEnumerable collection of SymbolReferences. + IEnumerable ProvideDocumentSymbols(ScriptFile scriptFile); + } +} diff --git a/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs new file mode 100644 index 000000000..4091f580b --- /dev/null +++ b/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation.Language; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + /// + /// Provides an IDocumentSymbolProvider implementation for + /// enumerating test symbols in Pester test (tests.ps1) files. + /// + public class PesterDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + { + IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols( + ScriptFile scriptFile) + { + if (!scriptFile.FilePath.EndsWith( + "tests.ps1", + StringComparison.OrdinalIgnoreCase)) + { + return Enumerable.Empty(); + } + + var commandAsts = scriptFile.ScriptAst.FindAll(ast => + { + switch ((ast as CommandAst)?.GetCommandName()?.ToLower()) + { + case "describe": + case "context": + case "it": + return true; + + default: + return false; + } + }, + true); + + return commandAsts.Select(ast => new SymbolReference( + SymbolType.Function, + ast.Extent, + scriptFile.FilePath, + scriptFile.GetLine(ast.Extent.StartLineNumber))); + } + } +} diff --git a/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs new file mode 100644 index 000000000..574d649cb --- /dev/null +++ b/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + /// + /// Provides an IDocumentSymbolProvider implementation for + /// enumerating symbols in .psd1 files. + /// + public class PsdDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + { + IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols( + ScriptFile scriptFile) + { + if ((scriptFile.FilePath != null && + scriptFile.FilePath.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) || + AstOperations.IsPowerShellDataFileAst(scriptFile.ScriptAst)) + { + var findHashtableSymbolsVisitor = new FindHashtableSymbolsVisitor(); + scriptFile.ScriptAst.Visit(findHashtableSymbolsVisitor); + return findHashtableSymbolsVisitor.SymbolReferences; + } + + return Enumerable.Empty(); + } + } +} diff --git a/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs new file mode 100644 index 000000000..40c8b93ca --- /dev/null +++ b/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.PowerShell.EditorServices.Symbols +{ + /// + /// Provides an IDocumentSymbolProvider implementation for + /// enumerating symbols in script (.psd1, .psm1) files. + /// + public class ScriptDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + { + private Version powerShellVersion; + + /// + /// Creates an instance of the ScriptDocumentSymbolProvider to + /// target the specified PowerShell version. + /// + /// The target PowerShell version. + public ScriptDocumentSymbolProvider(Version powerShellVersion) + { + this.powerShellVersion = powerShellVersion; + } + + IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols( + ScriptFile scriptFile) + { + if (scriptFile != null && + scriptFile.FilePath != null && + (scriptFile.FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase) || + scriptFile.FilePath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase))) + { + return + AstOperations.FindSymbolsInDocument( + scriptFile.ScriptAst, + this.powerShellVersion); + } + + return Enumerable.Empty(); + } + } +} From e6d7671374a97045c7b6d2fa87c4a66ec4824c78 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 7 Jun 2017 17:50:21 -0700 Subject: [PATCH 4/5] Add ICodeLenses and ICodeLensProvider interfaces and implementations This change adds the ICodeLenses and ICodeLensProvider interfaces and their implementations to establish the provider model for CodeLenses in the editor. --- .../CodeLens/CodeLensExtensions.cs | 47 ++++++ .../CodeLens/CodeLensFeature.cs | 159 ++++++++++++++++++ .../CodeLens/IScriptExtentExtensions.cs | 30 ++++ .../CodeLens/ReferencesCodeLensProvider.cs | 104 ++++++++++++ .../Commands/ClientCommandExtensions.cs | 31 ++++ .../EditorServicesHost.cs | 2 + .../LanguageServer/CodeLens.cs | 56 ++++++ .../LanguageServer/ServerCapabilities.cs | 2 +- .../LanguageServer/ServerCommand.cs | 28 +++ .../Server/LanguageServer.cs | 1 + .../CodeLenses/CodeLens.cs | 127 ++++++++++++++ .../CodeLenses/ICodeLensProvider.cs | 46 +++++ .../CodeLenses/ICodeLenses.cs | 34 ++++ .../Commands/ClientCommand.cs | 46 +++++ .../Language/AstOperations.cs | 14 +- .../Language/FindSymbolVisitor.cs | 18 +- .../Language/LanguageService.cs | 29 ++++ .../Workspace/ScriptRegion.cs | 15 +- 18 files changed, 781 insertions(+), 8 deletions(-) create mode 100644 src/PowerShellEditorServices.Host/CodeLens/CodeLensExtensions.cs create mode 100644 src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs create mode 100644 src/PowerShellEditorServices.Host/CodeLens/IScriptExtentExtensions.cs create mode 100644 src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs create mode 100644 src/PowerShellEditorServices.Host/Commands/ClientCommandExtensions.cs create mode 100644 src/PowerShellEditorServices.Protocol/LanguageServer/CodeLens.cs create mode 100644 src/PowerShellEditorServices.Protocol/LanguageServer/ServerCommand.cs create mode 100644 src/PowerShellEditorServices/CodeLenses/CodeLens.cs create mode 100644 src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs create mode 100644 src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs create mode 100644 src/PowerShellEditorServices/Commands/ClientCommand.cs diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensExtensions.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensExtensions.cs new file mode 100644 index 000000000..c3be72bfe --- /dev/null +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensExtensions.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Management.Automation.Language; +using Microsoft.PowerShell.EditorServices.CodeLenses; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using LanguageServer = Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; + +namespace Microsoft.PowerShell.EditorServices +{ + public static class ICodeLensExtensions + { + public static LanguageServer.CodeLens ToProtocolCodeLens( + this CodeLens codeLens, + JsonSerializer jsonSerializer) + { + return new LanguageServer.CodeLens + { + Range = codeLens.ScriptExtent.ToRange(), + Command = codeLens.Command.ToProtocolCommand(jsonSerializer) + }; + } + + public static LanguageServer.CodeLens ToProtocolCodeLens( + this CodeLens codeLens, + object codeLensData, + JsonSerializer jsonSerializer) + { + LanguageServer.ServerCommand command = null; + + if (codeLens.Command != null) + { + command = codeLens.Command.ToProtocolCommand(jsonSerializer); + } + + return new LanguageServer.CodeLens + { + Range = codeLens.ScriptExtent.ToRange(), + Data = JToken.FromObject(codeLensData, jsonSerializer), + Command = command + }; + } + } +} diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs new file mode 100644 index 000000000..b790081ae --- /dev/null +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -0,0 +1,159 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Components; +using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; +using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; +using Microsoft.PowerShell.EditorServices.Utility; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using LanguageServer = Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; + +namespace Microsoft.PowerShell.EditorServices.CodeLenses +{ + internal class CodeLensFeature : ICodeLenses + { + private EditorSession editorSession; + + private JsonSerializer jsonSerializer = + JsonSerializer.Create( + Constants.JsonSerializerSettings); + + public IProviderCollection Providers { get; } = + new ProviderCollection(); + + public CodeLensFeature( + EditorSession editorSession, + IMessageHandlers messageHandlers, + ILogger logger) + { + this.editorSession = editorSession; + + messageHandlers.SetRequestHandler( + CodeLensRequest.Type, + this.HandleCodeLensRequest); + + messageHandlers.SetRequestHandler( + CodeLensResolveRequest.Type, + this.HandleCodeLensResolveRequest); + } + + public static CodeLensFeature Create( + IComponentRegistry components, + EditorSession editorSession) + { + var codeLenses = + new CodeLensFeature( + editorSession, + components.Get(), + components.Get()); + + codeLenses.Providers.Add( + new ReferencesCodeLensProvider( + editorSession)); + + + editorSession.Components.Register(codeLenses); + + return codeLenses; + } + + public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) + { + return + this.Providers + .SelectMany(p => p.ProvideCodeLenses(scriptFile)) + .ToArray(); + } + + private async Task HandleCodeLensRequest( + CodeLensRequest codeLensParams, + RequestContext requestContext) + { + JsonSerializer jsonSerializer = + JsonSerializer.Create( + Constants.JsonSerializerSettings); + + var scriptFile = + this.editorSession.Workspace.GetFile( + codeLensParams.TextDocument.Uri); + + var codeLenses = + this.ProvideCodeLenses(scriptFile) + .Select( + codeLens => + codeLens.ToProtocolCodeLens( + new CodeLensData + { + Uri = codeLens.File.ClientFilePath, + ProviderId = codeLens.Provider.ProviderId + }, + this.jsonSerializer)) + .ToArray(); + + await requestContext.SendResult(codeLenses); + } + + private async Task HandleCodeLensResolveRequest( + LanguageServer.CodeLens codeLens, + RequestContext requestContext) + { + if (codeLens.Data != null) + { + // TODO: Catch deserializtion exception on bad object + CodeLensData codeLensData = codeLens.Data.ToObject(); + + ICodeLensProvider originalProvider = + this.Providers.FirstOrDefault( + provider => provider.ProviderId.Equals(codeLensData.ProviderId)); + + if (originalProvider != null) + { + ScriptFile scriptFile = + this.editorSession.Workspace.GetFile( + codeLensData.Uri); + + ScriptRegion region = new ScriptRegion + { + StartLineNumber = codeLens.Range.Start.Line + 1, + StartColumnNumber = codeLens.Range.Start.Character + 1, + EndLineNumber = codeLens.Range.End.Line + 1, + EndColumnNumber = codeLens.Range.End.Character + 1 + }; + + CodeLens originalCodeLens = + new CodeLens( + originalProvider, + scriptFile, + region); + + var resolvedCodeLens = + await originalProvider.ResolveCodeLensAsync( + originalCodeLens, + CancellationToken.None); + + await requestContext.SendResult( + resolvedCodeLens.ToProtocolCodeLens( + this.jsonSerializer)); + } + else + { + // TODO: Write error! + } + } + } + + private class CodeLensData + { + public string Uri { get; set; } + + public string ProviderId {get; set; } + } + } +} \ No newline at end of file diff --git a/src/PowerShellEditorServices.Host/CodeLens/IScriptExtentExtensions.cs b/src/PowerShellEditorServices.Host/CodeLens/IScriptExtentExtensions.cs new file mode 100644 index 000000000..ca8f49d54 --- /dev/null +++ b/src/PowerShellEditorServices.Host/CodeLens/IScriptExtentExtensions.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Management.Automation.Language; +using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; + +namespace Microsoft.PowerShell.EditorServices +{ + public static class IScriptExtentExtensions + { + public static Range ToRange(this IScriptExtent scriptExtent) + { + return new Range + { + Start = new Position + { + Line = scriptExtent.StartLineNumber - 1, + Character = scriptExtent.StartColumnNumber - 1 + }, + End = new Position + { + Line = scriptExtent.EndLineNumber - 1, + Character = scriptExtent.EndColumnNumber - 1 + } + }; + } + } +} diff --git a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs new file mode 100644 index 000000000..9d05785cb --- /dev/null +++ b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs @@ -0,0 +1,104 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.PowerShell.EditorServices.Commands; +using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; +using Microsoft.PowerShell.EditorServices.Symbols; + +namespace Microsoft.PowerShell.EditorServices.CodeLenses +{ + internal class ReferencesCodeLensProvider : ProviderBase, ICodeLensProvider + { + private EditorSession editorSession; + private IDocumentSymbolProvider symbolProvider; + + public ReferencesCodeLensProvider(EditorSession editorSession) + { + this.editorSession = editorSession; + + // TODO: Pull this from components + this.symbolProvider = + new ScriptDocumentSymbolProvider( + editorSession.PowerShellContext.LocalPowerShellVersion.Version); + } + + public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) + { + return + this.symbolProvider + .ProvideDocumentSymbols(scriptFile) + .Where(symbol => symbol.SymbolType == SymbolType.Function) + .Select( + symbol => + new CodeLens( + this, + scriptFile, + symbol.ScriptRegion)) + .ToArray(); + } + + public async Task ResolveCodeLensAsync( + CodeLens codeLens, + CancellationToken cancellationToken) + { + ScriptFile[] references = + editorSession.Workspace.ExpandScriptReferences( + codeLens.File); + + var foundSymbol = + this.editorSession.LanguageService.FindFunctionDefinitionAtLocation( + codeLens.File, + codeLens.ScriptExtent.StartLineNumber, + codeLens.ScriptExtent.StartColumnNumber); + + FindReferencesResult referencesResult = + await editorSession.LanguageService.FindReferencesOfSymbol( + foundSymbol, + references, + editorSession.Workspace); + + var referenceLocations = + referencesResult + .FoundReferences + .Select( + r => new Location + { + Uri = GetFileUri(r.FilePath), + Range = r.ScriptRegion.ToRange() + }) + .ToArray(); + + return + new CodeLens( + codeLens, + new ClientCommand( + "editor.action.showReferences", + referenceLocations.Length == 1 + ? "1 reference" + : $"{referenceLocations.Length} references", + new object[] + { + codeLens.File.ClientFilePath, + codeLens.ScriptExtent.ToRange().Start, + referenceLocations, + } + )); + } + + private static string GetFileUri(string filePath) + { + // If the file isn't untitled, return a URI-style path + return + !filePath.StartsWith("untitled") + ? new Uri("file://" + filePath).AbsoluteUri + : filePath; + } + } +} \ No newline at end of file diff --git a/src/PowerShellEditorServices.Host/Commands/ClientCommandExtensions.cs b/src/PowerShellEditorServices.Host/Commands/ClientCommandExtensions.cs new file mode 100644 index 000000000..95594d9b6 --- /dev/null +++ b/src/PowerShellEditorServices.Host/Commands/ClientCommandExtensions.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Commands; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using LanguageServer = Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; + +namespace Microsoft.PowerShell.EditorServices +{ + public static class ClientCommandExtensions + { + public static LanguageServer.ServerCommand ToProtocolCommand( + this ClientCommand clientCommand, + JsonSerializer jsonSerializer) + { + return new LanguageServer.ServerCommand + { + Command = clientCommand.Name, + Title = clientCommand.Title, + Arguments = + JArray.FromObject( + clientCommand.Arguments, + jsonSerializer) + }; + } + } +} diff --git a/src/PowerShellEditorServices.Host/EditorServicesHost.cs b/src/PowerShellEditorServices.Host/EditorServicesHost.cs index fc1ea00c9..8c9c7f9a2 100644 --- a/src/PowerShellEditorServices.Host/EditorServicesHost.cs +++ b/src/PowerShellEditorServices.Host/EditorServicesHost.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using Microsoft.PowerShell.EditorServices.CodeLenses; using Microsoft.PowerShell.EditorServices.Extensions; using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel; @@ -353,6 +354,7 @@ private EditorSession CreateSession( editorSession.Components.Register(messageSender); editorSession.Components.Register(powerShellContext); + CodeLensFeature.Create(editorSession.Components, editorSession); DocumentSymbolFeature.Create(editorSession.Components, editorSession); return editorSession; diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/CodeLens.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/CodeLens.cs new file mode 100644 index 000000000..fd12f284d --- /dev/null +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/CodeLens.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; +using Newtonsoft.Json.Linq; + +namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer +{ + /// + /// Code Lens options. + /// + public class CodeLensOptions + { + /// + /// Code lens has a resolve provider as well. + /// + public bool ResolveProvider { get; set; } + } + + public class CodeLens + { + public Range Range { get; set; } + + public ServerCommand Command { get; set; } + + public JToken Data { get; set; } + } + + /// + /// A code lens represents a command that should be shown along with + /// source text, like the number of references, a way to run tests, etc. + /// + /// A code lens is _unresolved_ when no command is associated to it. For performance + /// reasons the creation of a code lens and resolving should be done in two stages. + /// + public class CodeLensRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/codeLens"); + + /// + /// The document to request code lens for. + /// + public TextDocumentIdentifier TextDocument { get; set; } + } + + public class CodeLensResolveRequest + { + public static readonly + RequestType Type = + RequestType.Create("codeLens/resolve"); + } +} diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCapabilities.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCapabilities.cs index 26fec4ae1..2279e64d6 100644 --- a/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCapabilities.cs +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCapabilities.cs @@ -27,7 +27,7 @@ public class ServerCapabilities public bool? CodeActionProvider { get; set; } - public bool? CodeLensProvider { get; set; } + public CodeLensOptions CodeLensProvider { get; set; } public bool? DocumentFormattingProvider { get; set; } diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCommand.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCommand.cs new file mode 100644 index 000000000..b299b5606 --- /dev/null +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/ServerCommand.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Newtonsoft.Json.Linq; + +namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer +{ + public class ServerCommand + { + /// + /// Title of the command, like `save`. + /// + public string Title { get; set; } + + /// + /// The identifier of the actual command handler. + /// + public string Command { get; set; } + + /// + /// Arguments that the command handler should be + /// invoked with. + /// + public JArray Arguments { get; set; } + } +} \ No newline at end of file diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 8f056f255..39a38dee1 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -186,6 +186,7 @@ await requestContext.SendResult( WorkspaceSymbolProvider = true, HoverProvider = true, CodeActionProvider = true, + CodeLensProvider = new CodeLensOptions { ResolveProvider = true }, CompletionProvider = new CompletionOptions { ResolveProvider = true, diff --git a/src/PowerShellEditorServices/CodeLenses/CodeLens.cs b/src/PowerShellEditorServices/CodeLenses/CodeLens.cs new file mode 100644 index 000000000..2fd251595 --- /dev/null +++ b/src/PowerShellEditorServices/CodeLenses/CodeLens.cs @@ -0,0 +1,127 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Commands; +using Microsoft.PowerShell.EditorServices.Utility; +using System.Collections.Generic; +using System.Management.Automation.Language; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.EditorServices.CodeLenses +{ + /// + /// Defines the data for a "code lens" which is displayed + /// above a symbol in a text document and has an associated + /// command. + /// + public class CodeLens + { + /// + /// Gets the ICodeLensProvider that created this CodeLens. + /// + public ICodeLensProvider Provider { get; private set; } + + /// + /// Gets the ScriptFile for which the CodeLens was created. + /// + public ScriptFile File { get; private set; } + + /// + /// Gets the IScriptExtent for the region which the CodeLens + /// pertains. + /// + public IScriptExtent ScriptExtent { get; private set; } + + /// + /// Gets the command which will be invoked in the editor + /// when the CodeLens is clicked. + /// + public ClientCommand Command { get; private set; } + + /// + /// Creates an instance of the CodeLens class. + /// + /// + /// The ICodeLensProvider which created this CodeLens. + /// + /// + /// The ScriptFile for which the CodeLens was created. + /// + /// + /// The IScriptExtent for the region which the CodeLens + /// pertains. + /// + public CodeLens( + ICodeLensProvider provider, + ScriptFile scriptFile, + IScriptExtent scriptExtent) + : this( + provider, + scriptFile, + scriptExtent, + null) + { + } + + /// + /// Creates an instance of the CodeLens class based on an + /// original CodeLens instance, generally used when resolving + /// the Command for a CodeLens. + /// + /// + /// The original CodeLens upon which this instance is based. + /// + /// + /// The resolved ClientCommand for the original CodeLens. + /// + public CodeLens( + CodeLens originalCodeLens, + ClientCommand resolvedCommand) + { + Validate.IsNotNull(nameof(originalCodeLens), originalCodeLens); + Validate.IsNotNull(nameof(resolvedCommand), resolvedCommand); + + this.Provider = originalCodeLens.Provider; + this.File = originalCodeLens.File; + this.ScriptExtent = originalCodeLens.ScriptExtent; + this.Command = resolvedCommand; + } + + /// + /// Creates an instance of the CodeLens class. + /// + /// + /// The ICodeLensProvider which created this CodeLens. + /// + /// + /// The ScriptFile for which the CodeLens was created. + /// + /// + /// The IScriptExtent for the region which the CodeLens + /// pertains. + /// + /// + /// The ClientCommand to execute when this CodeLens is clicked. + /// If null, this CodeLens will be resolved by the editor when it + /// gets displayed. + /// + public CodeLens( + ICodeLensProvider provider, + ScriptFile scriptFile, + IScriptExtent scriptExtent, + ClientCommand command) + { + Validate.IsNotNull(nameof(provider), provider); + Validate.IsNotNull(nameof(scriptFile), scriptFile); + Validate.IsNotNull(nameof(scriptExtent), scriptExtent); + + this.Provider = provider; + this.File = scriptFile; + this.ScriptExtent = scriptExtent; + this.Command = command; + } + } +} diff --git a/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs b/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs new file mode 100644 index 000000000..abf5d0a37 --- /dev/null +++ b/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Utility; +using System.Collections.Generic; +using System.Management.Automation.Language; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.EditorServices.CodeLenses +{ + /// + /// Specifies the contract for a Code Lens provider. + /// + public interface ICodeLensProvider : IProvider + { + /// + /// Provides a collection of CodeLenses for the given + /// document. + /// + /// + /// The document for which CodeLenses should be provided. + /// + /// An array of CodeLenses. + CodeLens[] ProvideCodeLenses(ScriptFile scriptFile); + + /// + /// Resolves a CodeLens that was created without a Command. + /// + /// + /// The CodeLens to resolve. + /// + /// + /// A CancellationToken which can be used to cancel the + /// request. + /// + /// + /// A Task which returns the resolved CodeLens when completed. + /// + Task ResolveCodeLensAsync( + CodeLens codeLens, + CancellationToken cancellationToken); + } +} diff --git a/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs b/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs new file mode 100644 index 000000000..9f8e87211 --- /dev/null +++ b/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.EditorServices.CodeLenses +{ + /// + /// Specifies the contract for an implementation of + /// the ICodeLenses component. + /// + public interface ICodeLenses + { + /// + /// Gets the collection of ICodeLensProvider implementations + /// that are registered with this component. + /// + IProviderCollection Providers { get; } + + /// + /// Provides a collection of CodeLenses for the given + /// document. + /// + /// + /// The document for which CodeLenses should be provided. + /// + /// An array of CodeLenses. + CodeLens[] ProvideCodeLenses(ScriptFile scriptFile); + } +} diff --git a/src/PowerShellEditorServices/Commands/ClientCommand.cs b/src/PowerShellEditorServices/Commands/ClientCommand.cs new file mode 100644 index 000000000..42ee9a147 --- /dev/null +++ b/src/PowerShellEditorServices/Commands/ClientCommand.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.PowerShell.EditorServices.Commands +{ + /// + /// Provides details for a command which will be executed + /// in the host editor. + /// + public class ClientCommand + { + /// + /// Gets the identifying name of the command. + /// + public string Name { get; private set; } + + /// + /// Gets the display title of the command. + /// + public string Title { get; private set; } + + /// + /// Gets the array of objects which are passed as + /// arguments to the command. + /// + public object[] Arguments { get; private set; } + + /// + /// Creates an instance of the ClientCommand class. + /// + /// The name of the command. + /// The display title of the command. + /// The arguments to be passed to the command. + public ClientCommand( + string commandName, + string commandTitle, + object[] arguments) + { + this.Name = commandName; + this.Title = commandTitle; + this.Arguments = arguments; + } + } +} diff --git a/src/PowerShellEditorServices/Language/AstOperations.cs b/src/PowerShellEditorServices/Language/AstOperations.cs index 48ecf1b26..c28416280 100644 --- a/src/PowerShellEditorServices/Language/AstOperations.cs +++ b/src/PowerShellEditorServices/Language/AstOperations.cs @@ -145,10 +145,20 @@ static public async Task GetCompletions( /// The abstract syntax tree of the given script /// The line number of the cursor for the given script /// The coulumn number of the cursor for the given script + /// Includes full function definition ranges in the search. /// SymbolReference of found symbol - static public SymbolReference FindSymbolAtPosition(Ast scriptAst, int lineNumber, int columnNumber) + static public SymbolReference FindSymbolAtPosition( + Ast scriptAst, + int lineNumber, + int columnNumber, + bool includeFunctionDefinitions = false) { - FindSymbolVisitor symbolVisitor = new FindSymbolVisitor(lineNumber, columnNumber); + FindSymbolVisitor symbolVisitor = + new FindSymbolVisitor( + lineNumber, + columnNumber, + includeFunctionDefinitions); + scriptAst.Visit(symbolVisitor); return symbolVisitor.FoundSymbolReference; diff --git a/src/PowerShellEditorServices/Language/FindSymbolVisitor.cs b/src/PowerShellEditorServices/Language/FindSymbolVisitor.cs index aeef67abb..b2abea291 100644 --- a/src/PowerShellEditorServices/Language/FindSymbolVisitor.cs +++ b/src/PowerShellEditorServices/Language/FindSymbolVisitor.cs @@ -14,13 +14,18 @@ internal class FindSymbolVisitor : AstVisitor { private int lineNumber; private int columnNumber; + private bool includeFunctionDefinitions; public SymbolReference FoundSymbolReference { get; private set; } - public FindSymbolVisitor(int lineNumber, int columnNumber) + public FindSymbolVisitor( + int lineNumber, + int columnNumber, + bool includeFunctionDefinitions) { this.lineNumber = lineNumber; this.columnNumber = columnNumber; + this.includeFunctionDefinitions = includeFunctionDefinitions; } /// @@ -54,9 +59,14 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) /// or a decision to continue if it wasn't found public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { - int startColumnNumber = - functionDefinitionAst.Extent.Text.IndexOf( - functionDefinitionAst.Name) + 1; + int startColumnNumber = 1; + + if (!this.includeFunctionDefinitions) + { + startColumnNumber = + functionDefinitionAst.Extent.Text.IndexOf( + functionDefinitionAst.Name) + 1; + } IScriptExtent nameExtent = new ScriptExtent() { diff --git a/src/PowerShellEditorServices/Language/LanguageService.cs b/src/PowerShellEditorServices/Language/LanguageService.cs index 0dffd271e..44439a12b 100644 --- a/src/PowerShellEditorServices/Language/LanguageService.cs +++ b/src/PowerShellEditorServices/Language/LanguageService.cs @@ -196,6 +196,35 @@ public SymbolReference FindSymbolAtLocation( return symbolReference; } + /// + /// Finds a function definition in the script given a file location + /// + /// The details and contents of a open script file + /// The line number of the cursor for the given script + /// The coulumn number of the cursor for the given script + /// A SymbolReference of the symbol found at the given location + /// or null if there is no symbol at that location + /// + public SymbolReference FindFunctionDefinitionAtLocation( + ScriptFile scriptFile, + int lineNumber, + int columnNumber) + { + SymbolReference symbolReference = + AstOperations.FindSymbolAtPosition( + scriptFile.ScriptAst, + lineNumber, + columnNumber, + includeFunctionDefinitions: true); + + if (symbolReference != null) + { + symbolReference.FilePath = scriptFile.FilePath; + } + + return symbolReference; + } + /// /// Finds the details of the symbol at the given script file location. /// diff --git a/src/PowerShellEditorServices/Workspace/ScriptRegion.cs b/src/PowerShellEditorServices/Workspace/ScriptRegion.cs index 803fe8dd4..5775ddee6 100644 --- a/src/PowerShellEditorServices/Workspace/ScriptRegion.cs +++ b/src/PowerShellEditorServices/Workspace/ScriptRegion.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System; using System.Management.Automation.Language; namespace Microsoft.PowerShell.EditorServices @@ -10,7 +11,7 @@ namespace Microsoft.PowerShell.EditorServices /// /// Contains details about a specific region of text in script file. /// - public sealed class ScriptRegion + public sealed class ScriptRegion : IScriptExtent { #region Properties @@ -54,6 +55,18 @@ public sealed class ScriptRegion /// public int EndOffset { get; set; } + /// + /// Gets the starting IScriptPosition in the script. + /// (Currently unimplemented.) + /// + IScriptPosition IScriptExtent.StartScriptPosition => throw new NotImplementedException(); + + /// + /// Gets the ending IScriptPosition in the script. + /// (Currently unimplemented.) + /// + IScriptPosition IScriptExtent.EndScriptPosition => throw new NotImplementedException(); + #endregion #region Constructors From 956e3f7deab18f7470395f74b747731f284857f3 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 8 Jun 2017 06:45:04 -0700 Subject: [PATCH 5/5] Rename "Provider" to "FeatureProvider" This name change will help the purpose of this design to be more obvious and also distinguish it from other PowerShell features that are called "providers." --- .../CodeLens/CodeLensFeature.cs | 4 ++-- .../CodeLens/ReferencesCodeLensProvider.cs | 2 +- .../Symbols/DocumentSymbolFeature.cs | 4 ++-- .../CodeLenses/ICodeLensProvider.cs | 2 +- src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs | 2 +- .../{ProviderBase.cs => FeatureProviderBase.cs} | 4 ++-- ...viderCollection.cs => FeatureProviderCollection.cs} | 10 +++++----- .../Providers/{IProvider.cs => IFeatureProvider.cs} | 4 ++-- ...iderCollection.cs => IFeatureProviderCollection.cs} | 4 ++-- .../Symbols/IDocumentSymbolProvider.cs | 2 +- .../Symbols/IDocumentSymbols.cs | 2 +- .../Symbols/PesterDocumentSymbolProvider.cs | 2 +- .../Symbols/PsdDocumentSymbolProvider.cs | 2 +- .../Symbols/ScriptDocumentSymbolProvider.cs | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) rename src/PowerShellEditorServices/Providers/{ProviderBase.cs => FeatureProviderBase.cs} (78%) rename src/PowerShellEditorServices/Providers/{ProviderCollection.cs => FeatureProviderCollection.cs} (72%) rename src/PowerShellEditorServices/Providers/{IProvider.cs => IFeatureProvider.cs} (81%) rename src/PowerShellEditorServices/Providers/{IProviderCollection.cs => IFeatureProviderCollection.cs} (81%) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index b790081ae..9f6008694 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -25,8 +25,8 @@ internal class CodeLensFeature : ICodeLenses JsonSerializer.Create( Constants.JsonSerializerSettings); - public IProviderCollection Providers { get; } = - new ProviderCollection(); + public IFeatureProviderCollection Providers { get; } = + new FeatureProviderCollection(); public CodeLensFeature( EditorSession editorSession, diff --git a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs index 9d05785cb..3d1efc79d 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses { - internal class ReferencesCodeLensProvider : ProviderBase, ICodeLensProvider + internal class ReferencesCodeLensProvider : FeatureProviderBase, ICodeLensProvider { private EditorSession editorSession; private IDocumentSymbolProvider symbolProvider; diff --git a/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs b/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs index 27f72af83..5f2e9ba9d 100644 --- a/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs +++ b/src/PowerShellEditorServices.Host/Symbols/DocumentSymbolFeature.cs @@ -21,8 +21,8 @@ internal class DocumentSymbolFeature : IDocumentSymbols { private EditorSession editorSession; - public IProviderCollection Providers { get; } = - new ProviderCollection(); + public IFeatureProviderCollection Providers { get; } = + new FeatureProviderCollection(); public DocumentSymbolFeature( EditorSession editorSession, diff --git a/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs b/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs index abf5d0a37..71a1c0243 100644 --- a/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs +++ b/src/PowerShellEditorServices/CodeLenses/ICodeLensProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses /// /// Specifies the contract for a Code Lens provider. /// - public interface ICodeLensProvider : IProvider + public interface ICodeLensProvider : IFeatureProvider { /// /// Provides a collection of CodeLenses for the given diff --git a/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs b/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs index 9f8e87211..f63319c1c 100644 --- a/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs +++ b/src/PowerShellEditorServices/CodeLenses/ICodeLenses.cs @@ -19,7 +19,7 @@ public interface ICodeLenses /// Gets the collection of ICodeLensProvider implementations /// that are registered with this component. /// - IProviderCollection Providers { get; } + IFeatureProviderCollection Providers { get; } /// /// Provides a collection of CodeLenses for the given diff --git a/src/PowerShellEditorServices/Providers/ProviderBase.cs b/src/PowerShellEditorServices/Providers/FeatureProviderBase.cs similarity index 78% rename from src/PowerShellEditorServices/Providers/ProviderBase.cs rename to src/PowerShellEditorServices/Providers/FeatureProviderBase.cs index 35fa94335..ecf8e8ce2 100644 --- a/src/PowerShellEditorServices/Providers/ProviderBase.cs +++ b/src/PowerShellEditorServices/Providers/FeatureProviderBase.cs @@ -6,9 +6,9 @@ namespace Microsoft.PowerShell.EditorServices { /// - /// Provides a base implementation of IProvider. + /// Provides a base implementation of IFeatureProvider. /// - public abstract class ProviderBase : IProvider + public abstract class FeatureProviderBase : IFeatureProvider { /// /// Gets the provider class type's FullName as the diff --git a/src/PowerShellEditorServices/Providers/ProviderCollection.cs b/src/PowerShellEditorServices/Providers/FeatureProviderCollection.cs similarity index 72% rename from src/PowerShellEditorServices/Providers/ProviderCollection.cs rename to src/PowerShellEditorServices/Providers/FeatureProviderCollection.cs index 272ceab5c..fd4e1b1c9 100644 --- a/src/PowerShellEditorServices/Providers/ProviderCollection.cs +++ b/src/PowerShellEditorServices/Providers/FeatureProviderCollection.cs @@ -10,10 +10,10 @@ namespace Microsoft.PowerShell.EditorServices { /// - /// Provides a default implementation of IProviderCollection. + /// Provides a default implementation of IFeatureProviderCollection. /// - public class ProviderCollection : IProviderCollection - where TProvider : IProvider + public class FeatureProviderCollection : IFeatureProviderCollection + where TProvider : IFeatureProvider { #region Private Fields @@ -21,9 +21,9 @@ public class ProviderCollection : IProviderCollection #endregion - #region IProviderCollection Implementation + #region IFeatureProviderCollection Implementation - void IProviderCollection.Add(TProvider provider) + void IFeatureProviderCollection.Add(TProvider provider) { if (!this.providerList.Contains(provider)) { diff --git a/src/PowerShellEditorServices/Providers/IProvider.cs b/src/PowerShellEditorServices/Providers/IFeatureProvider.cs similarity index 81% rename from src/PowerShellEditorServices/Providers/IProvider.cs rename to src/PowerShellEditorServices/Providers/IFeatureProvider.cs index fc12c9323..bea42b821 100644 --- a/src/PowerShellEditorServices/Providers/IProvider.cs +++ b/src/PowerShellEditorServices/Providers/IFeatureProvider.cs @@ -8,10 +8,10 @@ namespace Microsoft.PowerShell.EditorServices /// /// Defines the contract for a feature provider, particularly for provider identification. /// - public interface IProvider + public interface IFeatureProvider { /// - /// Specifies a unique identifier for a provider, typically a + /// Specifies a unique identifier for the feature provider, typically a /// fully-qualified name like "Microsoft.PowerShell.EditorServices.MyProvider" /// string ProviderId { get; } diff --git a/src/PowerShellEditorServices/Providers/IProviderCollection.cs b/src/PowerShellEditorServices/Providers/IFeatureProviderCollection.cs similarity index 81% rename from src/PowerShellEditorServices/Providers/IProviderCollection.cs rename to src/PowerShellEditorServices/Providers/IFeatureProviderCollection.cs index 5099c4699..29351a4a4 100644 --- a/src/PowerShellEditorServices/Providers/IProviderCollection.cs +++ b/src/PowerShellEditorServices/Providers/IFeatureProviderCollection.cs @@ -10,8 +10,8 @@ namespace Microsoft.PowerShell.EditorServices /// /// Defines the contract for a collection of provider implementations. /// - public interface IProviderCollection : IEnumerable - where TProvider : IProvider + public interface IFeatureProviderCollection : IEnumerable + where TProvider : IFeatureProvider { /// /// Adds a provider to the collection. diff --git a/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs index 171bcd3b7..02638c5b0 100644 --- a/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs +++ b/src/PowerShellEditorServices/Symbols/IDocumentSymbolProvider.cs @@ -10,7 +10,7 @@ namespace Microsoft.PowerShell.EditorServices.Symbols /// /// Specifies the contract for a document symbols provider. /// - public interface IDocumentSymbolProvider : IProvider + public interface IDocumentSymbolProvider : IFeatureProvider { /// /// Provides a list of symbols for the given document. diff --git a/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs b/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs index 3529666e5..6c1937627 100644 --- a/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs +++ b/src/PowerShellEditorServices/Symbols/IDocumentSymbols.cs @@ -17,7 +17,7 @@ public interface IDocumentSymbols /// Gets the collection of IDocumentSymbolsProvider implementations /// that are registered with this component. /// - IProviderCollection Providers { get; } + IFeatureProviderCollection Providers { get; } /// /// Provides a list of symbols for the given document. diff --git a/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs index 4091f580b..d249dbb9c 100644 --- a/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs +++ b/src/PowerShellEditorServices/Symbols/PesterDocumentSymbolProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.EditorServices.Symbols /// Provides an IDocumentSymbolProvider implementation for /// enumerating test symbols in Pester test (tests.ps1) files. /// - public class PesterDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + public class PesterDocumentSymbolProvider : FeatureProviderBase, IDocumentSymbolProvider { IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols( ScriptFile scriptFile) diff --git a/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs index 574d649cb..e6e0c4a32 100644 --- a/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs +++ b/src/PowerShellEditorServices/Symbols/PsdDocumentSymbolProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.EditorServices.Symbols /// Provides an IDocumentSymbolProvider implementation for /// enumerating symbols in .psd1 files. /// - public class PsdDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + public class PsdDocumentSymbolProvider : FeatureProviderBase, IDocumentSymbolProvider { IEnumerable IDocumentSymbolProvider.ProvideDocumentSymbols( ScriptFile scriptFile) diff --git a/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs index 40c8b93ca..9405bf479 100644 --- a/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs +++ b/src/PowerShellEditorServices/Symbols/ScriptDocumentSymbolProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.EditorServices.Symbols /// Provides an IDocumentSymbolProvider implementation for /// enumerating symbols in script (.psd1, .psm1) files. /// - public class ScriptDocumentSymbolProvider : ProviderBase, IDocumentSymbolProvider + public class ScriptDocumentSymbolProvider : FeatureProviderBase, IDocumentSymbolProvider { private Version powerShellVersion;