From 7bf0f357c1306dac999230ce6fe6362fa6ee9dfe Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:29:11 -0500 Subject: [PATCH 01/29] Modified previous ConstrainedLanguage changes to support spawning runspace based on InitialSessionState instead of just the LanguageMode of the InitialSessionState. --- .../BuildInfo.cs | 4 +- .../Commands/StartEditorServicesCommand.cs | 9 +- .../Configuration/EditorServicesConfig.cs | 6 +- .../Internal/EditorServicesRunner.cs | 2 +- .../Hosting/HostStartupInfo.cs | 13 +-- .../Properties/Resources.Designer.cs | 63 +++++++++++++ .../PowerShellContextService.cs | 90 +++++++++++++------ .../Symbols/Vistors/FindReferencesVisitor.cs | 58 ++---------- 8 files changed, 152 insertions(+), 93 deletions(-) create mode 100644 src/PowerShellEditorServices/Properties/Resources.Designer.cs diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs index f516c8a8e..ac804fb4b 100644 --- a/src/PowerShellEditorServices.Hosting/BuildInfo.cs +++ b/src/PowerShellEditorServices.Hosting/BuildInfo.cs @@ -5,7 +5,7 @@ namespace Microsoft.PowerShell.EditorServices.Hosting public static class BuildInfo { public static readonly string BuildVersion = ""; - public static readonly string BuildOrigin = ""; - public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2019-12-06T21:43:41", CultureInfo.InvariantCulture.DateTimeFormat); + public static readonly string BuildOrigin = "Development"; + public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); } } diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 9c24da69f..60edeff7e 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -202,6 +202,12 @@ public StartEditorServicesCommand() [Parameter] public string StartupBanner { get; set; } + /// + /// The desired InitialSessionState, useful for using PSES in a ConstrainedRunspace. + /// + [Parameter] + public InitialSessionState InitialSessionState { get; set; } + protected override void BeginProcessing() { #if DEBUG @@ -351,6 +357,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); + var initialSessionState = InitialSessionState ?? Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { FeatureFlags = FeatureFlags, @@ -359,7 +366,7 @@ private EditorServicesConfig CreateConfigObject() AdditionalModules = AdditionalModules, LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), - LanguageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode, + InitialSessionState = initialSessionState, ProfilePaths = new ProfilePathConfig { AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts), diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs index 7650a522b..8d0b334d0 100644 --- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs +++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Management.Automation; using System.Management.Automation.Host; +using System.Management.Automation.Runspaces; namespace Microsoft.PowerShell.EditorServices.Hosting { @@ -113,10 +114,9 @@ public EditorServicesConfig( public ProfilePathConfig ProfilePaths { get; set; } /// - /// The language mode inherited from the orginal PowerShell process. - /// This will be used when creating runspaces so that we honor the same language mode. + /// The InitialSessionState to use when creating runspaces. LanguageMode can be set here. /// - public PSLanguageMode LanguageMode { get; internal set; } + public InitialSessionState InitialSessionState { get; internal set; } public string StartupBanner { get; set; } = @" diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs index 730964127..5dc039415 100644 --- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs +++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs @@ -237,7 +237,7 @@ private HostStartupInfo CreateHostStartupInfo() profilePaths, _config.FeatureFlags, _config.AdditionalModules, - _config.LanguageMode, + _config.InitialSessionState, _config.LogPath, (int)_config.LogLevel, consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None, diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs index 5cd5232f9..949b87ebf 100644 --- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs +++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Management.Automation; using System.Management.Automation.Host; +using System.Management.Automation.Runspaces; namespace Microsoft.PowerShell.EditorServices.Hosting { @@ -91,10 +92,10 @@ public sealed class HostStartupInfo public string LogPath { get; } /// - /// The language mode inherited from the orginal PowerShell process. - /// This will be used when creating runspaces so that we honor the same language mode. + /// The initialSessionState will be inherited from the orginal PowerShell process. + /// This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// - public PSLanguageMode LanguageMode { get; } + public InitialSessionState InitialSessionState { get; } /// /// The minimum log level of log events to be logged. @@ -124,7 +125,7 @@ public sealed class HostStartupInfo /// The path to the user specific profile. /// Flags of features to enable. /// Names or paths of additional modules to import. - /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode. + /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// The path to log to. /// The minimum log event level. /// Enable console if true. @@ -137,7 +138,7 @@ public HostStartupInfo( ProfilePathInfo profilePaths, IReadOnlyList featureFlags, IReadOnlyList additionalModules, - PSLanguageMode languageMode, + InitialSessionState initialSessionState, string logPath, int logLevel, bool consoleReplEnabled, @@ -150,7 +151,7 @@ public HostStartupInfo( ProfilePaths = profilePaths; FeatureFlags = featureFlags ?? Array.Empty(); AdditionalModules = additionalModules ?? Array.Empty(); - LanguageMode = languageMode; + InitialSessionState = initialSessionState; LogPath = logPath; LogLevel = logLevel; ConsoleReplEnabled = consoleReplEnabled; diff --git a/src/PowerShellEditorServices/Properties/Resources.Designer.cs b/src/PowerShellEditorServices/Properties/Resources.Designer.cs new file mode 100644 index 000000000..2af8a59ea --- /dev/null +++ b/src/PowerShellEditorServices/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PowerShellEditorServices.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PowerShellEditorServices.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index fbbfbc9dc..d5be98d36 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -26,6 +26,9 @@ namespace Microsoft.PowerShell.EditorServices.Services { using System.Management.Automation; + using Microsoft.PowerShell.EditorServices.Handlers; + using Microsoft.PowerShell.EditorServices.Hosting; + using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; /// /// Manages the lifetime and usage of a PowerShell session. @@ -214,27 +217,33 @@ public static PowerShellContextService Create( hostUserInterface, logger); - Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode); + if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) + { + hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules.ToArray()); + hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); + } + Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); - - powerShellContext.ImportCommandsModuleAsync(); - // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize - foreach (string module in hostStartupInfo.AdditionalModules) + if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { - var command = - new PSCommand() - .AddCommand("Microsoft.PowerShell.Core\\Import-Module") - .AddParameter("Name", module); + powerShellContext.ImportCommandsModuleAsync(); + foreach (string module in hostStartupInfo.AdditionalModules) + { + var command = + new PSCommand() + .AddCommand("Microsoft.PowerShell.Core\\Import-Module") + .AddParameter("Name", module); #pragma warning disable CS4014 - // This call queues the loading on the pipeline thread, so no need to await - powerShellContext.ExecuteCommandAsync( - command, - sendOutputToHost: false, - sendErrorToHost: true); + // This call queues the loading on the pipeline thread, so no need to await + powerShellContext.ExecuteCommandAsync( + command, + sendOutputToHost: false, + sendErrorToHost: true); #pragma warning restore CS4014 + } } return powerShellContext; @@ -259,29 +268,52 @@ public static Runspace CreateRunspace( var psHost = new EditorServicesPSHost(powerShellContext, hostDetails, hostUserInterface, logger); powerShellContext.ConsoleWriter = hostUserInterface; powerShellContext.ConsoleReader = hostUserInterface; - return CreateRunspace(psHost, hostDetails.LanguageMode); + return CreateRunspace(psHost, hostDetails.InitialSessionState); + } + private static InitialSessionState GetUsefulConstrainedISS() + { + InitialSessionState iss = InitialSessionState.Create("Microsoft.PowerShell.Core"); + iss.LanguageMode = PSLanguageMode.ConstrainedLanguage; + iss.ImportPSModule(new string[] { "Microsoft.Powershell.Utility", "Microsoft.Powershell.Core", "Microsoft.PowerShell.Security" }); + + iss.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Get-ChildItem", typeof(PSCommand), null)); // + iss.Commands.Add(new SessionStateCmdletEntry("Export-ModuleMember", typeof(ExportModuleMemberCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Where-Object", typeof(WhereObjectCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Select-Object", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Set-Variable", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("ForEach-Object", typeof(ForEachObjectCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-List", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-Table", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Set-ExecutionPolicy", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-Hex", typeof(PSCommand), null)); + //iss.Commands.Add(new SessionStateCmdletEntry("Out-Default", typeof(OutDefaultCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Microsoft.PowerShell.Core\\Out-Default", typeof(OutDefaultCommand), null) { Visibility = SessionStateEntryVisibility.Public }); + iss.Commands.Add(new SessionStateCmdletEntry("Out-Host", typeof(OutHostCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Start-EditorServices", typeof(PSCommand), null)); + + return iss; } - /// /// /// /// The PSHost that will be used for this Runspace. - /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode. + /// The initialSessionState inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// - public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode) + public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) { - InitialSessionState initialSessionState; - if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") { - initialSessionState = InitialSessionState.CreateDefault(); - } else { - initialSessionState = InitialSessionState.CreateDefault2(); + if (initialSessionState == null) + { + if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") + { + initialSessionState = InitialSessionState.CreateDefault(); + } + else + { + initialSessionState = InitialSessionState.CreateDefault2(); + } } - - // Create and initialize a new Runspace while honoring the LanguageMode of the original runspace - // that started PowerShell Editor Services. This is because the PowerShell Integrated Console - // should have the same LanguageMode of whatever is set by the system. - initialSessionState.LanguageMode = languageMode; - Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs index 256cfe559..6e873272e 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs @@ -125,13 +125,17 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) /// A visit action that continues the search for references public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { - (int startColumnNumber, int startLineNumber) = GetStartColumnAndLineNumbersFromAst(functionDefinitionAst); + // Get the start column number of the function name, + // instead of the the start column of 'function' and create new extent for the functionName + int startColumnNumber = + functionDefinitionAst.Extent.Text.IndexOf( + functionDefinitionAst.Name) + 1; IScriptExtent nameExtent = new ScriptExtent() { Text = functionDefinitionAst.Name, - StartLineNumber = startLineNumber, - EndLineNumber = startLineNumber, + StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, + EndLineNumber = functionDefinitionAst.Extent.StartLineNumber, StartColumnNumber = startColumnNumber, EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length, File = functionDefinitionAst.Extent.File @@ -182,53 +186,5 @@ public override AstVisitAction VisitVariableExpression(VariableExpressionAst var } return AstVisitAction.Continue; } - - // Computes where the start of the actual function name is. - private static (int, int) GetStartColumnAndLineNumbersFromAst(FunctionDefinitionAst ast) - { - int startColumnNumber = ast.Extent.StartColumnNumber; - int startLineNumber = ast.Extent.StartLineNumber; - int astOffset = 0; - - if (ast.IsFilter) - { - astOffset = "filter".Length; - } - else if (ast.IsWorkflow) - { - astOffset = "workflow".Length; - } - else - { - astOffset = "function".Length; - } - - string astText = ast.Extent.Text; - // The line offset represents the offset on the line that we're on where as - // astOffset is the offset on the entire text of the AST. - int lineOffset = astOffset; - for (; astOffset < astText.Length; astOffset++, lineOffset++) - { - if (astText[astOffset] == '\n') - { - // reset numbers since we are operating on a different line and increment the line number. - startColumnNumber = 0; - startLineNumber++; - lineOffset = 0; - } - else if (astText[astOffset] == '\r') - { - // Do nothing with carriage returns... we only look for line feeds since those - // are used on every platform. - } - else if (!char.IsWhiteSpace(astText[astOffset])) - { - // This is the start of the function name so we've found our start column and line number. - break; - } - } - - return (startColumnNumber + lineOffset, startLineNumber); - } } } From e50beb5b7538cf03f65029185670e45f27531c24 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:31:01 -0500 Subject: [PATCH 02/29] Removed unused code for creating ConstrainedRunspace --- .../PowerShellContextService.cs | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index d5be98d36..a23f1bcfa 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -270,31 +270,7 @@ public static Runspace CreateRunspace( powerShellContext.ConsoleReader = hostUserInterface; return CreateRunspace(psHost, hostDetails.InitialSessionState); } - private static InitialSessionState GetUsefulConstrainedISS() - { - InitialSessionState iss = InitialSessionState.Create("Microsoft.PowerShell.Core"); - iss.LanguageMode = PSLanguageMode.ConstrainedLanguage; - iss.ImportPSModule(new string[] { "Microsoft.Powershell.Utility", "Microsoft.Powershell.Core", "Microsoft.PowerShell.Security" }); - - iss.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Get-ChildItem", typeof(PSCommand), null)); // - iss.Commands.Add(new SessionStateCmdletEntry("Export-ModuleMember", typeof(ExportModuleMemberCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Where-Object", typeof(WhereObjectCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Select-Object", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Set-Variable", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("ForEach-Object", typeof(ForEachObjectCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-List", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-Table", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Set-ExecutionPolicy", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-Hex", typeof(PSCommand), null)); - //iss.Commands.Add(new SessionStateCmdletEntry("Out-Default", typeof(OutDefaultCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Microsoft.PowerShell.Core\\Out-Default", typeof(OutDefaultCommand), null) { Visibility = SessionStateEntryVisibility.Public }); - iss.Commands.Add(new SessionStateCmdletEntry("Out-Host", typeof(OutHostCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Start-EditorServices", typeof(PSCommand), null)); - - return iss; - } + /// /// /// From e7e2bfe2b97f2d076bbeea99e518a9b5bc483975 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:49:53 -0500 Subject: [PATCH 03/29] Updated PowerShellContextFactory.cs to not specify a LanguageMode and instead provide null as the InitialSessionState which will result in the previous initialSessionStateLogic running as it was in FullLanguage mode. Updated incorrect ProjectReference path in PowerShellEditorServices.Test.Host.csproj but the test suite still doesn't run correctly. --- src/PowerShellEditorServices.Hosting/BuildInfo.cs | 2 +- test/PowerShellEditorServices.Test/PowerShellContextFactory.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs index ac804fb4b..6baaaa203 100644 --- a/src/PowerShellEditorServices.Hosting/BuildInfo.cs +++ b/src/PowerShellEditorServices.Hosting/BuildInfo.cs @@ -5,7 +5,7 @@ namespace Microsoft.PowerShell.EditorServices.Hosting public static class BuildInfo { public static readonly string BuildVersion = ""; - public static readonly string BuildOrigin = "Development"; + public static readonly string BuildOrigin = ""; public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); } } diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 7b5cb229c..2a1289714 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -46,7 +46,7 @@ public static PowerShellContextService Create(ILogger logger) TestProfilePaths, new List(), new List(), - PSLanguageMode.FullLanguage, + null, null, 0, consoleReplEnabled: false, From 0dc040e1f3740adb29729fb43b98f39b7195dab6 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:56:47 -0500 Subject: [PATCH 04/29] Removed unnecessary changes. --- .../Commands/StartEditorServicesCommand.cs | 6 -- .../PowerShellEditorServices.csproj | 6 +- .../Properties/Resources.Designer.cs | 63 ------------------- .../PowerShellContextService.cs | 3 +- 4 files changed, 7 insertions(+), 71 deletions(-) delete mode 100644 src/PowerShellEditorServices/Properties/Resources.Designer.cs diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 60edeff7e..eca6ca9af 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -202,12 +202,6 @@ public StartEditorServicesCommand() [Parameter] public string StartupBanner { get; set; } - /// - /// The desired InitialSessionState, useful for using PSES in a ConstrainedRunspace. - /// - [Parameter] - public InitialSessionState InitialSessionState { get; set; } - protected override void BeginProcessing() { #if DEBUG diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 7e28c7d94..8ec5b0e42 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -53,6 +53,10 @@ - + + + + + diff --git a/src/PowerShellEditorServices/Properties/Resources.Designer.cs b/src/PowerShellEditorServices/Properties/Resources.Designer.cs deleted file mode 100644 index 2af8a59ea..000000000 --- a/src/PowerShellEditorServices/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace PowerShellEditorServices.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PowerShellEditorServices.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index a23f1bcfa..64356decb 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -28,7 +28,7 @@ namespace Microsoft.PowerShell.EditorServices.Services using System.Management.Automation; using Microsoft.PowerShell.EditorServices.Handlers; using Microsoft.PowerShell.EditorServices.Hosting; - using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; + using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; /// /// Manages the lifetime and usage of a PowerShell session. @@ -226,6 +226,7 @@ public static PowerShellContextService Create( powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize + // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { powerShellContext.ImportCommandsModuleAsync(); From bbbcd072332ae78c3b777e250887951cd6cb5c89 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 19:27:57 -0500 Subject: [PATCH 05/29] Fixed compilation error. --- .../Commands/StartEditorServicesCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index eca6ca9af..726dc037f 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -351,7 +351,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); - var initialSessionState = InitialSessionState ?? Runspace.DefaultRunspace.InitialSessionState; + var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { FeatureFlags = FeatureFlags, From 6d425d21925675a45bfca252653ba09ba6fe9cd6 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Fri, 8 May 2020 09:10:51 -0500 Subject: [PATCH 06/29] Created internal overload for CreateRunspace that accepts InitialSessionState. Renamed initialRunspace to runspace Typecasted AdditionalModules instead of using .ToArray() to prevent cannot convert from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.IEnumerable' compile time error. This is not ready to be merged as it needs to be rebased on master to fix test issues, and the primary objective of the changes has not been met as CommandCompletion.CompleteInput returns 0 CompletionResults when spawned from a Constrained Runspace. This may or may not require a fix from the PowerShell team as we are spawning CompleteInput from an overload of CompleteCommand that uses TabExpansion2 and there is a comment in their code indicating that this (or something related to it) is currently broken: https://github.com/PowerShell/PowerShell/blob/f4382202ae4622bf26795e29a7b39b9d7cdfb3fb/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs#L547 --- .../Commands/StartEditorServicesCommand.cs | 1 + .../PowerShellEditorServices.csproj | 4 -- .../PowerShellContextService.cs | 39 +++++++++++-------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 726dc037f..1d305f6ef 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -351,6 +351,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); + // This ensures that all Runspaces are created with the same InitialSessionState as the runspace that started EditorServices var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 8ec5b0e42..e169172b0 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -55,8 +55,4 @@ - - - - diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 64356decb..dbbc7ac7e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -219,11 +219,11 @@ public static PowerShellContextService Create( if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { - hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules.ToArray()); + hostStartupInfo.InitialSessionState.ImportPSModule((IEnumerable)hostStartupInfo.AdditionalModules); hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); } - Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); - powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); + Runspace runspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); + powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. @@ -271,26 +271,15 @@ public static Runspace CreateRunspace( powerShellContext.ConsoleReader = hostUserInterface; return CreateRunspace(psHost, hostDetails.InitialSessionState); } - + /// /// /// /// The PSHost that will be used for this Runspace. /// The initialSessionState inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// - public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) + internal static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) { - if (initialSessionState == null) - { - if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") - { - initialSessionState = InitialSessionState.CreateDefault(); - } - else - { - initialSessionState = InitialSessionState.CreateDefault2(); - } - } Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode @@ -305,6 +294,24 @@ public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initial return runspace; } + /// + /// + /// + /// The PSHost that will be used for this Runspace. + /// Runspace object created from the specified PSHost + public static Runspace CreateRunspace(PSHost psHost) + { + InitialSessionState initialSessionState; + if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") + { + initialSessionState = InitialSessionState.CreateDefault(); + } + else + { + initialSessionState = InitialSessionState.CreateDefault2(); + } + return CreateRunspace(psHost, initialSessionState); + } /// /// Initializes a new instance of the PowerShellContext class using From fd0e3605cb4f4266d6666a321955c8faf819b834 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Fri, 8 May 2020 09:17:42 -0500 Subject: [PATCH 07/29] Removed comment --- .../Services/PowerShellContext/PowerShellContextService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index dbbc7ac7e..214f48b9e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -226,7 +226,6 @@ public static PowerShellContextService Create( powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize - // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { powerShellContext.ImportCommandsModuleAsync(); From 0548349f688517b5e5fbb311757b7d4ca9aa94ba Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:29:11 -0500 Subject: [PATCH 08/29] Modified previous ConstrainedLanguage changes to support spawning runspace based on InitialSessionState instead of just the LanguageMode of the InitialSessionState. --- .../PowerShellContextService.cs | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 214f48b9e..ee6a74802 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -28,7 +28,7 @@ namespace Microsoft.PowerShell.EditorServices.Services using System.Management.Automation; using Microsoft.PowerShell.EditorServices.Handlers; using Microsoft.PowerShell.EditorServices.Hosting; - using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; + using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; /// /// Manages the lifetime and usage of a PowerShell session. @@ -222,8 +222,8 @@ public static PowerShellContextService Create( hostStartupInfo.InitialSessionState.ImportPSModule((IEnumerable)hostStartupInfo.AdditionalModules); hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); } - Runspace runspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); - powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); + Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); + powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) @@ -270,15 +270,50 @@ public static Runspace CreateRunspace( powerShellContext.ConsoleReader = hostUserInterface; return CreateRunspace(psHost, hostDetails.InitialSessionState); } - + private static InitialSessionState GetUsefulConstrainedISS() + { + InitialSessionState iss = InitialSessionState.Create("Microsoft.PowerShell.Core"); + iss.LanguageMode = PSLanguageMode.ConstrainedLanguage; + iss.ImportPSModule(new string[] { "Microsoft.Powershell.Utility", "Microsoft.Powershell.Core", "Microsoft.PowerShell.Security" }); + + iss.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Get-ChildItem", typeof(PSCommand), null)); // + iss.Commands.Add(new SessionStateCmdletEntry("Export-ModuleMember", typeof(ExportModuleMemberCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Where-Object", typeof(WhereObjectCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Select-Object", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Set-Variable", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("ForEach-Object", typeof(ForEachObjectCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-List", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-Table", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Set-ExecutionPolicy", typeof(PSCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Format-Hex", typeof(PSCommand), null)); + //iss.Commands.Add(new SessionStateCmdletEntry("Out-Default", typeof(OutDefaultCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Microsoft.PowerShell.Core\\Out-Default", typeof(OutDefaultCommand), null) { Visibility = SessionStateEntryVisibility.Public }); + iss.Commands.Add(new SessionStateCmdletEntry("Out-Host", typeof(OutHostCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), null)); + iss.Commands.Add(new SessionStateCmdletEntry("Start-EditorServices", typeof(PSCommand), null)); + + return iss; + } /// /// /// /// The PSHost that will be used for this Runspace. /// The initialSessionState inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// - internal static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) + public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) { + if (initialSessionState == null) + { + if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") + { + initialSessionState = InitialSessionState.CreateDefault(); + } + else + { + initialSessionState = InitialSessionState.CreateDefault2(); + } + } Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode From 8af273ccdc8cf3c14597bf51cc6e48f50487d306 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:31:01 -0500 Subject: [PATCH 09/29] Removed unused code for creating ConstrainedRunspace --- .../PowerShellContextService.cs | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index ee6a74802..3adde1ae3 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -270,31 +270,7 @@ public static Runspace CreateRunspace( powerShellContext.ConsoleReader = hostUserInterface; return CreateRunspace(psHost, hostDetails.InitialSessionState); } - private static InitialSessionState GetUsefulConstrainedISS() - { - InitialSessionState iss = InitialSessionState.Create("Microsoft.PowerShell.Core"); - iss.LanguageMode = PSLanguageMode.ConstrainedLanguage; - iss.ImportPSModule(new string[] { "Microsoft.Powershell.Utility", "Microsoft.Powershell.Core", "Microsoft.PowerShell.Security" }); - - iss.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Get-ChildItem", typeof(PSCommand), null)); // - iss.Commands.Add(new SessionStateCmdletEntry("Export-ModuleMember", typeof(ExportModuleMemberCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Where-Object", typeof(WhereObjectCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Select-Object", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Set-Variable", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("ForEach-Object", typeof(ForEachObjectCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-List", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-Table", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Set-ExecutionPolicy", typeof(PSCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Format-Hex", typeof(PSCommand), null)); - //iss.Commands.Add(new SessionStateCmdletEntry("Out-Default", typeof(OutDefaultCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Microsoft.PowerShell.Core\\Out-Default", typeof(OutDefaultCommand), null) { Visibility = SessionStateEntryVisibility.Public }); - iss.Commands.Add(new SessionStateCmdletEntry("Out-Host", typeof(OutHostCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), null)); - iss.Commands.Add(new SessionStateCmdletEntry("Start-EditorServices", typeof(PSCommand), null)); - - return iss; - } + /// /// /// From fecc78f071262e1f30bb5709bd6bb0c84b29f419 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 17:56:47 -0500 Subject: [PATCH 10/29] Removed unnecessary changes. --- .../Services/PowerShellContext/PowerShellContextService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 3adde1ae3..4f0dd81fe 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -28,7 +28,7 @@ namespace Microsoft.PowerShell.EditorServices.Services using System.Management.Automation; using Microsoft.PowerShell.EditorServices.Handlers; using Microsoft.PowerShell.EditorServices.Hosting; - using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; + using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; /// /// Manages the lifetime and usage of a PowerShell session. @@ -226,6 +226,7 @@ public static PowerShellContextService Create( powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize + // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { powerShellContext.ImportCommandsModuleAsync(); From d418d2624c0f2e42d92f257521817c45b6d5f462 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Sun, 3 May 2020 19:27:57 -0500 Subject: [PATCH 11/29] Fixed compilation error. --- .../Commands/StartEditorServicesCommand.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 1d305f6ef..eca6ca9af 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -351,8 +351,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); - // This ensures that all Runspaces are created with the same InitialSessionState as the runspace that started EditorServices - var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; + var initialSessionState = InitialSessionState ?? Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { FeatureFlags = FeatureFlags, From 46f23246df090d7dab62d6da111746387541c619 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Fri, 8 May 2020 09:10:51 -0500 Subject: [PATCH 12/29] Created internal overload for CreateRunspace that accepts InitialSessionState. Renamed initialRunspace to runspace Typecasted AdditionalModules instead of using .ToArray() to prevent cannot convert from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.IEnumerable' compile time error. This is not ready to be merged as it needs to be rebased on master to fix test issues, and the primary objective of the changes has not been met as CommandCompletion.CompleteInput returns 0 CompletionResults when spawned from a Constrained Runspace. This may or may not require a fix from the PowerShell team as we are spawning CompleteInput from an overload of CompleteCommand that uses TabExpansion2 and there is a comment in their code indicating that this (or something related to it) is currently broken: https://github.com/PowerShell/PowerShell/blob/f4382202ae4622bf26795e29a7b39b9d7cdfb3fb/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs#L547 --- .../PowerShellContextService.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 4f0dd81fe..dbbc7ac7e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -222,8 +222,8 @@ public static PowerShellContextService Create( hostStartupInfo.InitialSessionState.ImportPSModule((IEnumerable)hostStartupInfo.AdditionalModules); hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); } - Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); - powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); + Runspace runspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); + powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. @@ -271,26 +271,15 @@ public static Runspace CreateRunspace( powerShellContext.ConsoleReader = hostUserInterface; return CreateRunspace(psHost, hostDetails.InitialSessionState); } - + /// /// /// /// The PSHost that will be used for this Runspace. /// The initialSessionState inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode. /// - public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) + internal static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState) { - if (initialSessionState == null) - { - if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") - { - initialSessionState = InitialSessionState.CreateDefault(); - } - else - { - initialSessionState = InitialSessionState.CreateDefault2(); - } - } Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode From a8753ee5fcb8367b784d3a0c4ea920ad091ae379 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Fri, 8 May 2020 09:17:42 -0500 Subject: [PATCH 13/29] Removed comment --- .../Services/PowerShellContext/PowerShellContextService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index dbbc7ac7e..214f48b9e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -226,7 +226,6 @@ public static PowerShellContextService Create( powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize - // Darren Kattan: I haven't tested it, but I have a feeling this entire bit of logic can be replaced with the bit above for non-FullLanguage mode. I think that was is cleaner anyway. if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { powerShellContext.ImportCommandsModuleAsync(); From d7ea74e43b28d9c03c636e26dd6eff8408698a8e Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Mon, 1 Jun 2020 00:52:31 -0500 Subject: [PATCH 14/29] This works in a constrained runspace, but performance poor as PSES continuously attempts to resolve missing cmdlets. --- .../Commands/StartEditorServicesCommand.cs | 2 +- .../Services/PowerShellContext/PowerShellContextService.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index eca6ca9af..726dc037f 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -351,7 +351,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); - var initialSessionState = InitialSessionState ?? Runspace.DefaultRunspace.InitialSessionState; + var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { FeatureFlags = FeatureFlags, diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 214f48b9e..26c4d9fc6 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -219,7 +219,8 @@ public static PowerShellContextService Create( if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { - hostStartupInfo.InitialSessionState.ImportPSModule((IEnumerable)hostStartupInfo.AdditionalModules); + if(hostStartupInfo.AdditionalModules.Count > 0) + hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules as string[]); hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); } Runspace runspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); @@ -445,7 +446,7 @@ public void Initialize( this.PromptContext = new LegacyReadLineContext(this); } - if (VersionUtils.IsWindows) + if (VersionUtils.IsWindows && initialRunspace.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { this.SetExecutionPolicy(); } @@ -2740,7 +2741,7 @@ Runspace IHostSupportsInteractiveSession.Runspace { get { - return this.CurrentRunspace.Runspace; + return this.CurrentRunspace?.Runspace; } } From 79f4b8cb4578e94d2a140b9a4710f92d2d67b380 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Mon, 1 Jun 2020 19:30:01 -0500 Subject: [PATCH 15/29] Added null check for profile when loaded from a Constrained Runspace --- .../Commands/StartEditorServicesCommand.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 726dc037f..dddfbe73f 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -361,14 +361,19 @@ private EditorServicesConfig CreateConfigObject() LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), InitialSessionState = initialSessionState, - ProfilePaths = new ProfilePathConfig + + }; + + if(profile != null) + { + editorServicesConfig.ProfilePaths = new ProfilePathConfig { AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts), AllUsersCurrentHost = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.CurrentHost), CurrentUserAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.CurrentUser, ProfileHostKind.AllHosts), CurrentUserCurrentHost = GetProfilePathFromProfileObject(profile, ProfileUserKind.CurrentUser, ProfileHostKind.CurrentHost), - }, - }; + }; + } if (StartupBanner != null) { From 6c7da2bf1a2e7a0af8a0df5710748565c8fc0943 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Tue, 2 Jun 2020 07:05:15 -0500 Subject: [PATCH 16/29] Added default TabExpansion2 implementation so PSES works out of the box in a constrained runspace --- .../EditorServicesLoader.cs | 9 ++- .../PowerShellContextService.cs | 63 ++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index f387063e5..e9eb95795 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -13,6 +13,7 @@ using SMA = System.Management.Automation; using System.Management.Automation; using System.Management.Automation.Runspaces; +using System.Linq; #if CoreCLR using System.Runtime.Loader; @@ -257,9 +258,15 @@ private void UpdatePSModulePath() } string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator); + string[] psModulePaths = psModulePath.Split(Path.PathSeparator); + if (psModulePaths.Any(a => a == _hostConfig.BundledModulePath)) + { + _logger.Log(PsesLogLevel.Verbose, $"PSModulePath already contains '{_hostConfig.BundledModulePath}'"); + return; + } + psModulePath = $"{psModulePath}{Path.PathSeparator}{_hostConfig.BundledModulePath}"; Environment.SetEnvironmentVariable("PSModulePath", psModulePath); - _logger.Log(PsesLogLevel.Verbose, $"Updated PSModulePath to: '{psModulePath}'"); } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 26c4d9fc6..70baab3e4 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -88,7 +88,61 @@ static PowerShellContextService() private readonly Stack runspaceStack = new Stack(); private int isCommandLoopRestarterSet; + /// + /// This is the default function to use for tab expansion. + /// + private static string tabExpansionFunctionText = @" +<# Options include: + RelativeFilePaths - [bool] + Always resolve file paths using Resolve-Path -Relative. + The default is to use some heuristics to guess if relative or absolute is better. + + To customize your own custom options, pass a hashtable to CompleteInput, e.g. + return [System.Management.Automation.CommandCompletion]::CompleteInput($inputScript, $cursorColumn, + @{ RelativeFilePaths=$false } +#> + +[CmdletBinding(DefaultParameterSetName = 'ScriptInputSet')] +Param( + [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)] + [string] $inputScript, + + [Parameter(ParameterSetName = 'ScriptInputSet', Position = 1)] + [int] $cursorColumn = $inputScript.Length, + [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 0)] + [System.Management.Automation.Language.Ast] $ast, + + [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 1)] + [System.Management.Automation.Language.Token[]] $tokens, + + [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 2)] + [System.Management.Automation.Language.IScriptPosition] $positionOfCursor, + + [Parameter(ParameterSetName = 'ScriptInputSet', Position = 2)] + [Parameter(ParameterSetName = 'AstInputSet', Position = 3)] + [Hashtable] $options = $null +) + +End +{ + if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet') + { + return [System.Management.Automation.CommandCompletion]::CompleteInput( + <#inputScript#> $inputScript, + <#cursorColumn#> $cursorColumn, + <#options#> $options) + } + else + { + return [System.Management.Automation.CommandCompletion]::CompleteInput( + <#ast#> $ast, + <#tokens#> $tokens, + <#positionOfCursor#> $positionOfCursor, + <#options#> $options) + } +} + "; #endregion #region Properties @@ -220,8 +274,15 @@ public static PowerShellContextService Create( if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { if(hostStartupInfo.AdditionalModules.Count > 0) + { hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules as string[]); - hostStartupInfo.InitialSessionState.ImportPSModule(new string[] { s_commandsModulePath }); + } + + hostStartupInfo.InitialSessionState.ImportPSModule(new [] { s_commandsModulePath }); + if(!hostStartupInfo.InitialSessionState.Commands.Any(a=> a.Name.ToLower() == "tabexpansion2")) + { + hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateFunctionEntry("TabExpansion2", tabExpansionFunctionText)); + } } Runspace runspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); powerShellContext.Initialize(hostStartupInfo.ProfilePaths, runspace, true, hostUserInterface); From 3ba1f4e670f52a8970142fb72fee9e0f2029c1a5 Mon Sep 17 00:00:00 2001 From: Darren Kattan Date: Tue, 2 Jun 2020 08:31:12 -0500 Subject: [PATCH 17/29] Added Default InitialSessionState to test suite --- test/PowerShellEditorServices.Test/PowerShellContextFactory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 2a1289714..42460e1da 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.IO; using System.Management.Automation; +using System.Management.Automation.Runspaces; using System.Threading; using System.Threading.Tasks; @@ -46,7 +47,7 @@ public static PowerShellContextService Create(ILogger logger) TestProfilePaths, new List(), new List(), - null, + InitialSessionState.CreateDefault(), null, 0, consoleReplEnabled: false, From db87496723e8db2fccc5a944170b557280bc1ebc Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Wed, 2 Jun 2021 18:38:42 -0500 Subject: [PATCH 18/29] Modified code to work from a Constrained Runspace. --- .../Services/Analysis/AnalysisService.cs | 2 ++ .../PowerShellContextService.cs | 22 +++++++++++-------- .../Handlers/CodeActionHandler.cs | 11 ++++++---- .../Handlers/CompletionHandler.cs | 2 ++ .../Handlers/FoldingRangeHandler.cs | 2 +- .../Services/Workspace/WorkspaceService.cs | 1 + 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs index 11c604ccc..e99c67561 100644 --- a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs @@ -380,6 +380,8 @@ private async Task DelayThenInvokeDiagnosticsAsync(ScriptFile[] filesToAnalyze, foreach (ScriptFile scriptFile in filesToAnalyze) { + if (string.IsNullOrWhiteSpace(scriptFile.Contents)) + continue; ScriptFileMarker[] semanticMarkers = await AnalysisEngine.AnalyzeScriptAsync(scriptFile.Contents).ConfigureAwait(false); scriptFile.DiagnosticMarkers.AddRange(semanticMarkers); diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 6abd4ad9c..313cbf9f5 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -20,10 +20,12 @@ using Microsoft.PowerShell.EditorServices.Logging; using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; using Microsoft.PowerShell.EditorServices.Utility; +using Microsoft.PowerShell.Commands; namespace Microsoft.PowerShell.EditorServices.Services { using System.Management.Automation; + using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.EditorServices.Handlers; using Microsoft.PowerShell.EditorServices.Hosting; using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; @@ -271,7 +273,7 @@ public static PowerShellContextService Create( logger); logger.LogTrace("Creating initial PowerShell runspace"); - powerShellContext.ImportCommandsModuleAsync(); + if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { // Loading modules with ImportPSModule into the InitialSessionState because in constrained language mode there is no file system access. @@ -280,18 +282,20 @@ public static PowerShellContextService Create( { hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules as string[]); } - - hostStartupInfo.InitialSessionState.ImportPSModule(new [] { s_commandsModulePath }); - if(!hostStartupInfo.InitialSessionState.Commands.Any(a=> a.Name.ToLower() == "tabexpansion2")) + + hostStartupInfo.InitialSessionState.ImportPSModule(new[] { s_commandsModulePath }); + if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name.ToLower() == "tabexpansion2")) { hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateFunctionEntry("TabExpansion2", tabExpansionFunctionText)); } } + + // DO NOT MOVE THIS. The initialization above has to get done before we create the initial runspace. Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState); powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize - if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) + if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage || true) { powerShellContext.ImportCommandsModuleAsync(); foreach (string module in hostStartupInfo.AdditionalModules) @@ -300,7 +304,7 @@ public static PowerShellContextService Create( new PSCommand() .AddCommand("Microsoft.PowerShell.Core\\Import-Module") .AddParameter("Name", module); - + #pragma warning disable CS4014 // This call queues the loading on the pipeline thread, so no need to await powerShellContext.ExecuteCommandAsync( @@ -707,7 +711,7 @@ public async Task> ExecuteCommandAsync( // via PowerShell eventing // 4. The command cannot be for a PSReadLine pipeline while we // are currently in a out of process runspace - var threadController = PromptNest.GetThreadController(); + var threadController = PromptNest?.GetThreadController(); if (!(threadController == null || !threadController.IsPipelineThread || threadController.IsCurrentThread() || @@ -826,7 +830,7 @@ public async Task> ExecuteCommandAsync( // Due to the following PowerShell bug, we can't just assign shell.Commands to psCommand // because PowerShell strips out CommandInfo: - // https://github.com/PowerShell/PowerShell/issues/12297 + // https://github.com/PowerShell/PowerShell/hostStartupInfo.InitialSessionStateues/12297 shell.Commands.Clear(); foreach (Command command in psCommand.Commands) { @@ -1163,7 +1167,7 @@ public async Task ExecuteScriptWithArgsAsync(string script, string arguments = n // . Any embedded single quotes are escaped. // If the provided path is already quoted, then File.Exists will not find it. // This keeps us from quoting an already quoted path. - // Related to issue #123. + // Related to hostStartupInfo.InitialSessionStateue #123. if (File.Exists(script) || File.Exists(scriptAbsPath)) { // Dot-source the launched script path and single quote the path in case it includes diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index 5c2529225..1012e8dd7 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -57,10 +57,13 @@ public override async Task Handle(CodeActionParams } // On Windows, VSCode still gives us file URIs like "file:///c%3a/...", so we need to escape them - IReadOnlyDictionary corrections = await _analysisService.GetMostRecentCodeActionsForFileAsync( - _workspaceService.GetFile(request.TextDocument.Uri)).ConfigureAwait(false); - - if (corrections == null) + IReadOnlyDictionary corrections = null; + try + { + corrections = await _analysisService.GetMostRecentCodeActionsForFileAsync( + _workspaceService.GetFile(request.TextDocument.Uri)).ConfigureAwait(false); + } + catch (Exception ex) //if (corrections == null) { return Array.Empty(); } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs index 94f74a5b2..570d1a22c 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs @@ -58,6 +58,8 @@ public async Task Handle(CompletionParams request, CancellationT int cursorLine = request.Position.Line + 1; int cursorColumn = request.Position.Character + 1; + + ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); try diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs index effe2af58..7343c7a17 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs @@ -34,7 +34,7 @@ public PsesFoldingRangeHandler(ILoggerFactory factory, ConfigurationService conf public override Task> Handle(FoldingRangeRequestParam request, CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) { _logger.LogDebug("FoldingRange request canceled for file: {0}", request.TextDocument.Uri); return Task.FromResult(new Container()); diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs index 8ea3b77f5..67b24fee9 100644 --- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs @@ -194,6 +194,7 @@ public bool TryGetFile(DocumentUri documentUri, out ScriptFile scriptFile) case "file": case "untitled": case "vscode-notebook-cell": + case "inmemory": break; default: From 99854df76c01a0bf57baea53ef5abf51d8dbee2d Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:14:19 -0500 Subject: [PATCH 19/29] Got modules to load as expected in Constrained Runspace by switching to ImportPSModulesFromPath. PSScriptAnalyzer load fails with "The following error occurred while loading the extended type data file: Error in TypeData "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.RuleInfo": " --- .../PowerShellContext/PowerShellContextService.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 313cbf9f5..8600a61e2 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -277,13 +277,16 @@ public static PowerShellContextService Create( if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { // Loading modules with ImportPSModule into the InitialSessionState because in constrained language mode there is no file system access. - // This may not be entirely true and needs to be tested. if (hostStartupInfo.AdditionalModules.Count > 0) { hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules as string[]); } - hostStartupInfo.InitialSessionState.ImportPSModule(new[] { s_commandsModulePath }); + // ImportPSModule throws System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' + // ImportPSModulesFromPath loads the module fine + hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(s_commandsModulePath); //C:\Users\dkattan\Source\Repos\immybot\core\backend\Immybot.Backend.Web\bin\Commands\PowerShellEditorServices.Commands.psd1 + hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(@"%UserProfile%\Source\Repos\immybot\core\backend\Immybot.Backend.Web\bin\Debug\net5.0\vendor\PSES\module\PSScriptAnalyzer"); + if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name.ToLower() == "tabexpansion2")) { hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateFunctionEntry("TabExpansion2", tabExpansionFunctionText)); @@ -295,7 +298,8 @@ public static PowerShellContextService Create( powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); // TODO: This can be moved to the point after the $psEditor object // gets initialized when that is done earlier than LanguageServer.Initialize - if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage || true) + // When importing modules like this in a Constrained Runspace it fails with System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' + if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { powerShellContext.ImportCommandsModuleAsync(); foreach (string module in hostStartupInfo.AdditionalModules) From 7111814ff246ba85d32d3f3fe88ab453d4ccc388 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Mon, 7 Jun 2021 08:27:39 -0500 Subject: [PATCH 20/29] Removed reference to local profile --- .../Services/PowerShellContext/PowerShellContextService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 8600a61e2..55247fc20 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -284,8 +284,7 @@ public static PowerShellContextService Create( // ImportPSModule throws System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' // ImportPSModulesFromPath loads the module fine - hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(s_commandsModulePath); //C:\Users\dkattan\Source\Repos\immybot\core\backend\Immybot.Backend.Web\bin\Commands\PowerShellEditorServices.Commands.psd1 - hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(@"%UserProfile%\Source\Repos\immybot\core\backend\Immybot.Backend.Web\bin\Debug\net5.0\vendor\PSES\module\PSScriptAnalyzer"); + hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(s_commandsModulePath); if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name.ToLower() == "tabexpansion2")) { From bdd993c559a6e7ea1c26c15d731c88a1dad6bcf6 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:17:17 -0500 Subject: [PATCH 21/29] Removed BuildInfo.cs --- src/PowerShellEditorServices.Hosting/BuildInfo.cs | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/PowerShellEditorServices.Hosting/BuildInfo.cs diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs deleted file mode 100644 index 83f53946d..000000000 --- a/src/PowerShellEditorServices.Hosting/BuildInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Globalization; - -namespace Microsoft.PowerShell.EditorServices.Hosting -{ - public static class BuildInfo - { - // TODO: Include a Git commit hash in this. - public static readonly string BuildVersion = ""; - public static readonly string BuildOrigin = ""; - public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); - } -} From 1f738a64c80f4fa505e7c50d1ab55988d411002b Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:22:09 -0500 Subject: [PATCH 22/29] Revert "Removed BuildInfo.cs" This reverts commit bdd993c559a6e7ea1c26c15d731c88a1dad6bcf6. --- src/PowerShellEditorServices.Hosting/BuildInfo.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/PowerShellEditorServices.Hosting/BuildInfo.cs diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs new file mode 100644 index 000000000..83f53946d --- /dev/null +++ b/src/PowerShellEditorServices.Hosting/BuildInfo.cs @@ -0,0 +1,12 @@ +using System.Globalization; + +namespace Microsoft.PowerShell.EditorServices.Hosting +{ + public static class BuildInfo + { + // TODO: Include a Git commit hash in this. + public static readonly string BuildVersion = ""; + public static readonly string BuildOrigin = ""; + public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); + } +} From bce339670221929bbf34570fe40eec1db2700047 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:23:13 -0500 Subject: [PATCH 23/29] Undoing changes to BuildInfo.cs --- src/PowerShellEditorServices.Hosting/BuildInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs index 83f53946d..78953ca18 100644 --- a/src/PowerShellEditorServices.Hosting/BuildInfo.cs +++ b/src/PowerShellEditorServices.Hosting/BuildInfo.cs @@ -4,9 +4,9 @@ namespace Microsoft.PowerShell.EditorServices.Hosting { public static class BuildInfo { - // TODO: Include a Git commit hash in this. public static readonly string BuildVersion = ""; public static readonly string BuildOrigin = ""; - public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); + public static readonly string BuildCommit = ""; + public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2019-12-06T21:43:41", CultureInfo.InvariantCulture.DateTimeFormat); } } From 124bd9502d3ecde6c7ea009015a1313a24602892 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:23:13 -0500 Subject: [PATCH 24/29] Undoing changes to BuildInfo.cs --- src/PowerShellEditorServices.Hosting/BuildInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/BuildInfo.cs b/src/PowerShellEditorServices.Hosting/BuildInfo.cs index 83f53946d..253d0f9a0 100644 --- a/src/PowerShellEditorServices.Hosting/BuildInfo.cs +++ b/src/PowerShellEditorServices.Hosting/BuildInfo.cs @@ -5,8 +5,8 @@ namespace Microsoft.PowerShell.EditorServices.Hosting public static class BuildInfo { // TODO: Include a Git commit hash in this. - public static readonly string BuildVersion = ""; + public static readonly string BuildVersion = ""; public static readonly string BuildOrigin = ""; - public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2020-05-03T16:39:35", CultureInfo.InvariantCulture.DateTimeFormat); + public static readonly System.DateTime? BuildTime = System.DateTime.Parse("2019-12-06T21:43:41", CultureInfo.InvariantCulture.DateTimeFormat); } } From 54196a8be013c85087e8c2b35716a5ce38eb19c2 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:33:02 -0500 Subject: [PATCH 25/29] Added comment indicating the purpose of the InitialSessionState variable. --- .../Commands/StartEditorServicesCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index c7b4a669c..a85d49d13 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -349,6 +349,7 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); + // We will use the InitialSessionState that comes from the runspace that started Editor Services for all runspace creation in Editor Services var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { From 87b94c97803e55da23ff543f71f3406d74579c46 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 09:40:58 -0500 Subject: [PATCH 26/29] Removed profile null check changes as those are done differently in PR 1504. --- .../Commands/StartEditorServicesCommand.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index a85d49d13..96391f7c7 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -349,7 +349,6 @@ private EditorServicesConfig CreateConfigObject() var profile = (PSObject)GetVariableValue("profile"); var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion); - // We will use the InitialSessionState that comes from the runspace that started Editor Services for all runspace creation in Editor Services var initialSessionState = Runspace.DefaultRunspace.InitialSessionState; var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath) { @@ -359,20 +358,15 @@ private EditorServicesConfig CreateConfigObject() AdditionalModules = AdditionalModules, LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), - InitialSessionState = initialSessionState, - - }; - - if(profile != null) - { - editorServicesConfig.ProfilePaths = new ProfilePathConfig + InitialSessionState = initialSessionState, + ProfilePaths = new ProfilePathConfig { AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts), AllUsersCurrentHost = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.CurrentHost), CurrentUserAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.CurrentUser, ProfileHostKind.AllHosts), CurrentUserCurrentHost = GetProfilePathFromProfileObject(profile, ProfileUserKind.CurrentUser, ProfileHostKind.CurrentHost), - }; - } + }, + }; if (StartupBanner != null) { From c697af89a8105a5acd243cc09913bfb57cf2cea3 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:29:29 -0500 Subject: [PATCH 27/29] Adding comments, removing unnecessary changes. --- PowerShellEditorServices.build.ps1 | 132 ++++++++---------- build.ps1 | 30 ++-- .../Commands/StartEditorServicesCommand.cs | 2 +- .../EditorServicesLoader.cs | 12 +- .../PowerShellEditorServices.csproj | 2 +- .../PowerShellContextService.cs | 45 +++--- .../Symbols/Vistors/FindReferencesVisitor.cs | 62 ++++++-- .../Handlers/ConfigurationHandler.cs | 2 +- 8 files changed, 154 insertions(+), 133 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index d0b4a7844..01b698c9b 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -23,9 +23,9 @@ $script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditor $script:IsPreview = [bool]($script:PsesCommonProps.Project.PropertyGroup.VersionSuffix) $script:NetRuntime = @{ - PS7 = 'netcoreapp3.1' - PS72 = 'net6.0' - Desktop = 'net461' + PS7 = 'netcoreapp3.1' + PS72 = 'net6.0' + Desktop = 'net461' Standard = 'netstandard2.0' } @@ -42,11 +42,11 @@ if (Get-Command git -ErrorAction SilentlyContinue) { function Invoke-WithCreateDefaultHook { param([scriptblock]$ScriptBlock) - try - { + try { $env:PSES_TEST_USE_CREATE_DEFAULT = 1 & $ScriptBlock - } finally { + } + finally { Remove-Item env:PSES_TEST_USE_CREATE_DEFAULT } } @@ -69,25 +69,22 @@ function Install-Dotnet { Invoke-WebRequest "https://dot.net/v1/$installScript" -OutFile $installScriptPath # Download and install the different .NET channels - foreach ($dotnetChannel in $Channel) - { + foreach ($dotnetChannel in $Channel) { Write-Host "`n### Installing .NET CLI $Version...`n" if ($script:IsNix) { chmod +x $installScriptPath } - $params = if ($script:IsNix) - { + $params = if ($script:IsNix) { @('-Channel', $dotnetChannel, '-InstallDir', $env:DOTNET_INSTALL_DIR, '-NoPath', '-Verbose') } - else - { + else { @{ - Channel = $dotnetChannel + Channel = $dotnetChannel InstallDir = $env:DOTNET_INSTALL_DIR - NoPath = $true - Verbose = $true + NoPath = $true + Verbose = $true } } @@ -107,14 +104,13 @@ task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServe $dotnetExePath = if ($script:IsNix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } if (!(Test-Path $dotnetExePath)) { - # TODO: Test .NET 5 with PowerShell 7.1, and add that channel here. - Install-Dotnet -Channel '3.1','release/6.0.1xx-preview2' + # TODO: Test .NET 5 with PowerShell 7.1 + Install-Dotnet -Channel '3.1', '5.0', '6.0' } # This variable is used internally by 'dotnet' to know where it's installed $script:dotnetExe = Resolve-Path $dotnetExePath - if (!$env:DOTNET_INSTALL_DIR) - { + if (!$env:DOTNET_INSTALL_DIR) { $dotnetExeDir = [System.IO.Path]::GetDirectoryName($script:dotnetExe) $env:PATH = $dotnetExeDir + [System.IO.Path]::PathSeparator + $env:PATH $env:DOTNET_INSTALL_DIR = $dotnetExeDir @@ -129,7 +125,7 @@ task BinClean { Remove-Item $PSScriptRoot\module\PowerShellEditorServices.VSCode\bin -Recurse -Force -ErrorAction Ignore } -task Clean BinClean,{ +task Clean BinClean, { exec { & $script:dotnetExe restore } exec { & $script:dotnetExe clean } Get-ChildItem -Recurse $PSScriptRoot\src\*.nupkg | Remove-Item -Force -ErrorAction Ignore @@ -140,9 +136,9 @@ task Clean BinClean,{ $moduleJsonPath = "$PSScriptRoot\modules.json" if (Test-Path $moduleJsonPath) { Get-Content -Raw $moduleJsonPath | - ConvertFrom-Json | - ForEach-Object { $_.PSObject.Properties.Name } | - ForEach-Object { Remove-Item -Path "$PSScriptRoot/module/$_" -Recurse -Force -ErrorAction Ignore } + ConvertFrom-Json | + ForEach-Object { $_.PSObject.Properties.Name } | + ForEach-Object { Remove-Item -Path "$PSScriptRoot/module/$_" -Recurse -Force -ErrorAction Ignore } } } @@ -174,14 +170,17 @@ task GetProductVersion -Before PackageModule, UploadArtifacts { task CreateBuildInfo -Before Build { $buildVersion = "" $buildOrigin = "Development" + $buildCommit = git rev-parse HEAD # Set build info fields on build platforms if ($env:TF_BUILD) { if ($env:BUILD_BUILDNUMBER -like "PR-*") { $buildOrigin = "PR" - } elseif ($env:BUILD_DEFINITIONNAME -like "*-CI") { + } + elseif ($env:BUILD_DEFINITIONNAME -like "*-CI") { $buildOrigin = "CI" - } else { + } + else { $buildOrigin = "Release" } @@ -189,8 +188,7 @@ task CreateBuildInfo -Before Build { $propsBody = $propsXml.Project.PropertyGroup $buildVersion = $propsBody.VersionPrefix - if ($propsBody.VersionSuffix) - { + if ($propsBody.VersionSuffix) { $buildVersion += '-' + $propsBody.VersionSuffix } } @@ -215,6 +213,7 @@ namespace Microsoft.PowerShell.EditorServices.Hosting { public static readonly string BuildVersion = "$buildVersion"; public static readonly string BuildOrigin = "$buildOrigin"; + public static readonly string BuildCommit = "$buildCommit"; public static readonly System.DateTime? BuildTime = System.DateTime.Parse("$buildTime", CultureInfo.InvariantCulture.DateTimeFormat); } } @@ -228,17 +227,15 @@ task SetupHelpForTests { Write-Host "Updating help for tests" Update-Help -Module Microsoft.PowerShell.Utility -Force -Scope CurrentUser } - else - { + else { Write-Host "Write-Host help found -- Update-Help skipped" } } -task Build BinClean,{ +task Build BinClean, { exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard } exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 } - if (-not $script:IsNix) - { + if (-not $script:IsNix) { exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop } } @@ -248,12 +245,12 @@ task Build BinClean,{ function DotNetTestFilter { # Reference https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests - if ($TestFilter) { @("--filter",$TestFilter) } else { "" } + if ($TestFilter) { @("--filter", $TestFilter) } else { "" } } -task Test SetupHelpForTests,TestServer,TestE2E +task Test SetupHelpForTests, TestServer, TestE2E -task TestServer TestServerWinPS,TestServerPS7,TestServerPS72 +task TestServer TestServerWinPS, TestServerPS7, TestServerPS72 task TestServerWinPS -If (-not $script:IsNix) { Set-Location .\test\PowerShellEditorServices.Test\ @@ -286,7 +283,8 @@ task TestE2E { try { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine); exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } - } finally { + } + finally { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine); } } @@ -301,8 +299,7 @@ task LayoutModule -After Build { $psesCoreHostPath = "$psesBinOutputPath/Core" $psesDeskHostPath = "$psesBinOutputPath/Desktop" - foreach ($dir in $psesDepsPath,$psesCoreHostPath,$psesDeskHostPath,$psesVSCodeBinOutputPath) - { + foreach ($dir in $psesDepsPath, $psesCoreHostPath, $psesDeskHostPath, $psesVSCodeBinOutputPath) { New-Item -Force -Path $dir -ItemType Directory } @@ -315,37 +312,29 @@ task LayoutModule -After Build { [void]$includedDlls.Add('System.Management.Automation.dll') # PSES/bin/Common - foreach ($psesComponent in Get-ChildItem $script:PsesOutput) - { + foreach ($psesComponent in Get-ChildItem $script:PsesOutput) { if ($psesComponent.Name -eq 'System.Management.Automation.dll' -or - $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') - { + $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') { continue } - if ($psesComponent.Extension) - { + if ($psesComponent.Extension) { [void]$includedDlls.Add($psesComponent.Name) Copy-Item -Path $psesComponent.FullName -Destination $psesDepsPath -Force } } # PSES/bin/Core - foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) - { - if (-not $includedDlls.Contains($hostComponent.Name)) - { + foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) { + if (-not $includedDlls.Contains($hostComponent.Name)) { Copy-Item -Path $hostComponent.FullName -Destination $psesCoreHostPath -Force } } # PSES/bin/Desktop - if (-not $script:IsNix) - { - foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) - { - if (-not $includedDlls.Contains($hostComponent.Name)) - { + if (-not $script:IsNix) { + foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) { + if (-not $includedDlls.Contains($hostComponent.Name)) { Copy-Item -Path $hostComponent.FullName -Destination $psesDeskHostPath -Force } } @@ -353,10 +342,8 @@ task LayoutModule -After Build { # Assemble the PowerShellEditorServices.VSCode module - foreach ($vscodeComponent in Get-ChildItem $script:VSCodeOutput) - { - if (-not $includedDlls.Contains($vscodeComponent.Name)) - { + foreach ($vscodeComponent in Get-ChildItem $script:VSCodeOutput) { + if (-not $includedDlls.Contains($vscodeComponent.Name)) { Copy-Item -Path $vscodeComponent.FullName -Destination $psesVSCodeBinOutputPath -Force } } @@ -372,16 +359,15 @@ task RestorePsesModules -After Build { (Get-Content -Raw $ModulesJsonPath | ConvertFrom-Json).PSObject.Properties | ForEach-Object { $name = $_.Name $body = @{ - Name = $name - MinimumVersion = $_.Value.MinimumVersion - MaximumVersion = $_.Value.MaximumVersion + Name = $name + MinimumVersion = $_.Value.MinimumVersion + MaximumVersion = $_.Value.MaximumVersion AllowPrerelease = $script:IsPreview - Repository = if ($_.Value.Repository) { $_.Value.Repository } else { $DefaultModuleRepository } - Path = $submodulePath + Repository = if ($_.Value.Repository) { $_.Value.Repository } else { $DefaultModuleRepository } + Path = $submodulePath } - if (-not $name) - { + if (-not $name) { throw "EditorServices module listed without name in '$ModulesJsonPath'" } @@ -396,10 +382,8 @@ task RestorePsesModules -After Build { } # Save each module in the modules.json file - foreach ($moduleName in $moduleInfos.Keys) - { - if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) - { + foreach ($moduleName in $moduleInfos.Keys) { + if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) { Write-Host "`tModule '${moduleName}' already detected. Skipping" continue } @@ -407,10 +391,10 @@ task RestorePsesModules -After Build { $moduleInstallDetails = $moduleInfos[$moduleName] $splatParameters = @{ - Name = $moduleName - AllowPrerelease = $moduleInstallDetails.AllowPrerelease - Repository = if ($moduleInstallDetails.Repository) { $moduleInstallDetails.Repository } else { $DefaultModuleRepository } - Path = $submodulePath + Name = $moduleName + AllowPrerelease = $moduleInstallDetails.AllowPrerelease + Repository = if ($moduleInstallDetails.Repository) { $moduleInstallDetails.Repository } else { $DefaultModuleRepository } + Path = $submodulePath } # Only add Min and Max version if we're doing a stable release. @@ -446,4 +430,4 @@ task UploadArtifacts -If ($null -ne $env:TF_BUILD) { } # The default task is to run the entire CI build -task . GetProductVersion, Clean, Build, Test, BuildCmdletHelp, PackageModule, UploadArtifacts +task . GetProductVersion, Clean, Build, Test, BuildCmdletHelp, PackageModule, UploadArtifacts \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 913e907e4..a16e2925d 100644 --- a/build.ps1 +++ b/build.ps1 @@ -18,16 +18,18 @@ param( ) $NeededTools = @{ - OpenSsl = "openssl for macOS" + OpenSsl = "openssl for macOS" PowerShellGet = "PowerShellGet latest" - InvokeBuild = "InvokeBuild latest" + InvokeBuild = "InvokeBuild latest" } if ((-not $PSVersionTable["OS"]) -or $PSVersionTable["OS"].Contains("Windows")) { $OS = "Windows" -} elseif ($PSVersionTable["OS"].Contains("Darwin")) { +} +elseif ($PSVersionTable["OS"].Contains("Darwin")) { $OS = "macOS" -} else { +} +else { $OS = "Linux" } @@ -36,7 +38,8 @@ function needsOpenSsl () { if ($OS -eq "macOS") { try { $opensslVersion = (openssl version) - } catch { + } + catch { return $true } } @@ -82,22 +85,25 @@ if ($Bootstrap) { $missingTools = getMissingTools if (($missingTools).Count -eq 0) { $string += "* nothing!`n`n Run this script without a flag to build or a -Clean to clean." - } else { - $missingTools | ForEach-Object {$string += "* $_`n"} + } + else { + $missingTools | ForEach-Object { $string += "* $_`n" } $string += "`nAll instructions for installing these tools can be found on PowerShell Editor Services' Github:`n" ` + "https://github.com/powershell/PowerShellEditorServices#development" } Write-Host "`n$string`n" -} elseif(hasMissingTools) { +} +elseif (hasMissingTools) { Write-Host "You are missing needed tools. Run './build.ps1 -Bootstrap' to see what they are." -} else { - if($Clean) { +} +else { + if ($Clean) { Invoke-Build Clean } Invoke-Build Build - if($Test) { + if ($Test) { Invoke-Build Test } -} +} \ No newline at end of file diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 96391f7c7..26b4b06d1 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -358,7 +358,7 @@ private EditorServicesConfig CreateConfigObject() AdditionalModules = AdditionalModules, LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), - InitialSessionState = initialSessionState, + InitialSessionState = initialSessionState, ProfilePaths = new ProfilePathConfig { AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts), diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 2179e2b8a..0fbb5324a 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -11,7 +11,6 @@ using SMA = System.Management.Automation; using System.Management.Automation; using System.Management.Automation.Runspaces; -using System.Linq; #if CoreCLR using System.Runtime.Loader; @@ -255,16 +254,10 @@ private void UpdatePSModulePath() return; } - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator); - string[] psModulePaths = psModulePath.Split(Path.PathSeparator); - if (psModulePaths.Any(a => a == _hostConfig.BundledModulePath)) - { - _logger.Log(PsesLogLevel.Verbose, $"PSModulePath already contains '{_hostConfig.BundledModulePath}'"); - return; - } - + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator); psModulePath = $"{psModulePath}{Path.PathSeparator}{_hostConfig.BundledModulePath}"; Environment.SetEnvironmentVariable("PSModulePath", psModulePath); + _logger.Log(PsesLogLevel.Verbose, $"Updated PSModulePath to: '{psModulePath}'"); } @@ -276,6 +269,7 @@ private void LogHostInformation() == Build Details == - Editor Services version: {BuildInfo.BuildVersion} - Build origin: {BuildInfo.BuildOrigin} +- Build commit: {BuildInfo.BuildCommit} - Build time: {BuildInfo.BuildTime} "); diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 22889d77d..9b267f792 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -43,6 +43,6 @@ - + diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 55247fc20..29c3dcbbc 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -277,19 +277,31 @@ public static PowerShellContextService Create( if (hostStartupInfo.InitialSessionState.LanguageMode != PSLanguageMode.FullLanguage) { // Loading modules with ImportPSModule into the InitialSessionState because in constrained language mode there is no file system access. + // Import-Module provides the user with better errors, but may not be allowed within a constrained runspace + // ImportPSModule throws System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' + // ImportPSModulesFromPath loads the modules fine if (hostStartupInfo.AdditionalModules.Count > 0) - { hostStartupInfo.InitialSessionState.ImportPSModule(hostStartupInfo.AdditionalModules as string[]); - } - - // ImportPSModule throws System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' - // ImportPSModulesFromPath loads the module fine hostStartupInfo.InitialSessionState.ImportPSModulesFromPath(s_commandsModulePath); - + // Autocomplete will fail if there isn't an implementation of TabExpansion2 + // The default TabExpansion2 implementation may not be available in a Constrained Runspace, therefore we check and add it if not. + // Note: Attempting to set the visibility of these commands to Private will cause Autocomplete to fail if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name.ToLower() == "tabexpansion2")) { hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateFunctionEntry("TabExpansion2", tabExpansionFunctionText)); } + if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name == "Get-Command")) + { + hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null)); + // PSES called Get-Command by its Module Qualified Syntax "Microsoft.PowerShell.Core\Get-Command", but this fails in a Constrained Runspace + // Adding an alias to Get-Command by its module qualified syntax allows PSES to call it by "Microsoft.PowerShell.Core\Get-Command". + hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateAliasEntry(@"Microsoft.PowerShell.Core\Get-Command", "Get-Command", null)); + } + if (!hostStartupInfo.InitialSessionState.Commands.Any(a => a.Name == "Get-Help")) + { + hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateCmdletEntry("Get-Help", typeof(GetHelpCommand), null)); + hostStartupInfo.InitialSessionState.Commands.Add(new SessionStateAliasEntry(@"Microsoft.PowerShell.Core\Get-Help", "Get-Help", null)); + } } // DO NOT MOVE THIS. The initialization above has to get done before we create the initial runspace. @@ -300,7 +312,6 @@ public static PowerShellContextService Create( // When importing modules like this in a Constrained Runspace it fails with System.Management.Automation.DriveNotFoundException: 'Cannot find drive. A drive with the name 'C' does not exist.' if (hostStartupInfo.InitialSessionState.LanguageMode == PSLanguageMode.FullLanguage) { - powerShellContext.ImportCommandsModuleAsync(); foreach (string module in hostStartupInfo.AdditionalModules) { var command = @@ -365,24 +376,6 @@ internal static Runspace CreateRunspace(PSHost psHost, InitialSessionState initi return runspace; } - /// - /// - /// - /// The PSHost that will be used for this Runspace. - /// Runspace object created from the specified PSHost - public static Runspace CreateRunspace(PSHost psHost) - { - InitialSessionState initialSessionState; - if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") - { - initialSessionState = InitialSessionState.CreateDefault(); - } - else - { - initialSessionState = InitialSessionState.CreateDefault2(); - } - return CreateRunspace(psHost, initialSessionState); - } /// /// Initializes a new instance of the PowerShellContext class using @@ -1170,7 +1163,7 @@ public async Task ExecuteScriptWithArgsAsync(string script, string arguments = n // . Any embedded single quotes are escaped. // If the provided path is already quoted, then File.Exists will not find it. // This keeps us from quoting an already quoted path. - // Related to hostStartupInfo.InitialSessionStateue #123. + // Related to hostStartupInfo.InitialSessionState Issue #123. if (File.Exists(script) || File.Exists(scriptAbsPath)) { // Dot-source the launched script path and single quote the path in case it includes diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs index 8f9f8ed93..8d774e8df 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs @@ -68,7 +68,7 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) Ast commandNameAst = commandAst.CommandElements[0]; string commandName = commandNameAst.Extent.Text; - if(symbolRef.SymbolType.Equals(SymbolType.Function)) + if (symbolRef.SymbolType.Equals(SymbolType.Function)) { if (needsAliases) { @@ -123,17 +123,13 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) /// A visit action that continues the search for references public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { - // Get the start column number of the function name, - // instead of the the start column of 'function' and create new extent for the functionName - int startColumnNumber = - functionDefinitionAst.Extent.Text.IndexOf( - functionDefinitionAst.Name) + 1; + (int startColumnNumber, int startLineNumber) = GetStartColumnAndLineNumbersFromAst(functionDefinitionAst); IScriptExtent nameExtent = new ScriptExtent() { Text = functionDefinitionAst.Name, - StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, - EndLineNumber = functionDefinitionAst.Extent.StartLineNumber, + StartLineNumber = startLineNumber, + EndLineNumber = startLineNumber, StartColumnNumber = startColumnNumber, EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length, File = functionDefinitionAst.Extent.File @@ -175,7 +171,7 @@ public override AstVisitAction VisitCommandParameter(CommandParameterAst command /// A visit action that continues the search for references public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) { - if(symbolRef.SymbolType.Equals(SymbolType.Variable) && + if (symbolRef.SymbolType.Equals(SymbolType.Variable) && variableExpressionAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) { this.FoundReferences.Add(new SymbolReference( @@ -184,5 +180,53 @@ public override AstVisitAction VisitVariableExpression(VariableExpressionAst var } return AstVisitAction.Continue; } + + // Computes where the start of the actual function name is. + private static (int, int) GetStartColumnAndLineNumbersFromAst(FunctionDefinitionAst ast) + { + int startColumnNumber = ast.Extent.StartColumnNumber; + int startLineNumber = ast.Extent.StartLineNumber; + int astOffset = 0; + + if (ast.IsFilter) + { + astOffset = "filter".Length; + } + else if (ast.IsWorkflow) + { + astOffset = "workflow".Length; + } + else + { + astOffset = "function".Length; + } + + string astText = ast.Extent.Text; + // The line offset represents the offset on the line that we're on where as + // astOffset is the offset on the entire text of the AST. + int lineOffset = astOffset; + for (; astOffset < astText.Length; astOffset++, lineOffset++) + { + if (astText[astOffset] == '\n') + { + // reset numbers since we are operating on a different line and increment the line number. + startColumnNumber = 0; + startLineNumber++; + lineOffset = 0; + } + else if (astText[astOffset] == '\r') + { + // Do nothing with carriage returns... we only look for line feeds since those + // are used on every platform. + } + else if (!char.IsWhiteSpace(astText[astOffset])) + { + // This is the start of the function name so we've found our start column and line number. + break; + } + } + + return (startColumnNumber + lineOffset, startLineNumber); + } } } diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs index 073c176cb..2f4ca781f 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs @@ -51,7 +51,7 @@ public override async Task Handle(DidChangeConfigurationParams request, Ca { LanguageServerSettingsWrapper incomingSettings = request.Settings.ToObject(); this._logger.LogTrace("Handling DidChangeConfiguration"); - if (incomingSettings == null) + if (incomingSettings == null || incomingSettings.Powershell == null) { this._logger.LogTrace("Incoming settings were null"); return await Unit.Task.ConfigureAwait(false); From b893e08fd2d6e4ebd4074804ca22538844eba3c8 Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:34:34 -0500 Subject: [PATCH 28/29] Removing more unnecessary changes --- .../Services/Analysis/AnalysisService.cs | 21 +++++++++---------- .../Symbols/Vistors/FindReferencesVisitor.cs | 4 ++-- .../Handlers/CodeActionHandler.cs | 17 +++++++-------- .../Handlers/CompletionHandler.cs | 8 +++++-- .../Handlers/FoldingRangeHandler.cs | 13 ++++++------ .../Services/Workspace/WorkspaceService.cs | 4 ++-- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs index e99c67561..30d251d66 100644 --- a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs @@ -86,7 +86,7 @@ internal static string GetUniqueIdFromDiagnostic(Diagnostic diagnostic) private readonly ConfigurationService _configurationService; - private readonly WorkspaceService _workplaceService; + private readonly WorkspaceService _workspaceService; private readonly int _analysisDelayMillis; @@ -115,7 +115,7 @@ public AnalysisService( _logger = loggerFactory.CreateLogger(); _languageServer = languageServer; _configurationService = configurationService; - _workplaceService = workspaceService; + _workspaceService = workspaceService; _analysisDelayMillis = 750; _mostRecentCorrectionsByFile = new ConcurrentDictionary(); _analysisEngineLazy = new Lazy(InstantiateAnalysisEngine); @@ -223,9 +223,10 @@ public async Task GetCommentHelpText(string functionText, string helpLoc /// /// The URI string of the file to get code actions for. /// A threadsafe readonly dictionary of the code actions of the particular file. - public async Task> GetMostRecentCodeActionsForFileAsync(ScriptFile scriptFile) + public async Task> GetMostRecentCodeActionsForFileAsync(DocumentUri uri) { - if (!_mostRecentCorrectionsByFile.TryGetValue(scriptFile, out CorrectionTableEntry corrections)) + if (!_workspaceService.TryGetFile(uri, out ScriptFile file) + || !_mostRecentCorrectionsByFile.TryGetValue(file, out CorrectionTableEntry corrections)) { return null; } @@ -334,7 +335,7 @@ private bool TryFindSettingsFile(out string settingsFilePath) return false; } - settingsFilePath = _workplaceService.ResolveWorkspacePath(configuredPath); + settingsFilePath = _workspaceService.ResolveWorkspacePath(configuredPath); if (settingsFilePath == null || !File.Exists(settingsFilePath)) @@ -349,7 +350,7 @@ private bool TryFindSettingsFile(out string settingsFilePath) private void ClearOpenFileMarkers() { - foreach (ScriptFile file in _workplaceService.GetOpenedFiles()) + foreach (ScriptFile file in _workspaceService.GetOpenedFiles()) { ClearMarkers(file); } @@ -380,8 +381,6 @@ private async Task DelayThenInvokeDiagnosticsAsync(ScriptFile[] filesToAnalyze, foreach (ScriptFile scriptFile in filesToAnalyze) { - if (string.IsNullOrWhiteSpace(scriptFile.Contents)) - continue; ScriptFileMarker[] semanticMarkers = await AnalysisEngine.AnalyzeScriptAsync(scriptFile.Contents).ConfigureAwait(false); scriptFile.DiagnosticMarkers.AddRange(semanticMarkers); @@ -457,10 +456,10 @@ private static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel ma { switch (markerLevel) { - case ScriptFileMarkerLevel.Error: return DiagnosticSeverity.Error; - case ScriptFileMarkerLevel.Warning: return DiagnosticSeverity.Warning; + case ScriptFileMarkerLevel.Error: return DiagnosticSeverity.Error; + case ScriptFileMarkerLevel.Warning: return DiagnosticSeverity.Warning; case ScriptFileMarkerLevel.Information: return DiagnosticSeverity.Information; - default: return DiagnosticSeverity.Error; + default: return DiagnosticSeverity.Error; }; } diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs index 8d774e8df..a0dcb319b 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs @@ -68,7 +68,7 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) Ast commandNameAst = commandAst.CommandElements[0]; string commandName = commandNameAst.Extent.Text; - if (symbolRef.SymbolType.Equals(SymbolType.Function)) + if(symbolRef.SymbolType.Equals(SymbolType.Function)) { if (needsAliases) { @@ -171,7 +171,7 @@ public override AstVisitAction VisitCommandParameter(CommandParameterAst command /// A visit action that continues the search for references public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) { - if (symbolRef.SymbolType.Equals(SymbolType.Variable) && + if(symbolRef.SymbolType.Equals(SymbolType.Variable) && variableExpressionAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) { this.FoundReferences.Add(new SymbolReference( diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index 1012e8dd7..d550c0f7b 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -31,7 +31,7 @@ public PsesCodeActionHandler(ILoggerFactory factory, AnalysisService analysisSer } protected override CodeActionRegistrationOptions CreateRegistrationOptions(CodeActionCapability capability, ClientCapabilities clientCapabilities) => new CodeActionRegistrationOptions - { + { // TODO: What do we do with the arguments? DocumentSelector = LspUtils.PowerShellDocumentSelector, CodeActionKinds = new CodeActionKind[] { CodeActionKind.QuickFix } @@ -52,18 +52,15 @@ public override async Task Handle(CodeActionParams { if (cancellationToken.IsCancellationRequested) { - _logger.LogDebug("CodeAction request canceled at range: {0}", request.Range); + _logger.LogDebug($"CodeAction request canceled at range: {request.Range}"); return Array.Empty(); } - // On Windows, VSCode still gives us file URIs like "file:///c%3a/...", so we need to escape them - IReadOnlyDictionary corrections = null; - try - { - corrections = await _analysisService.GetMostRecentCodeActionsForFileAsync( - _workspaceService.GetFile(request.TextDocument.Uri)).ConfigureAwait(false); - } - catch (Exception ex) //if (corrections == null) + IReadOnlyDictionary corrections = await _analysisService.GetMostRecentCodeActionsForFileAsync( + request.TextDocument.Uri) + .ConfigureAwait(false); + + if (corrections == null) { return Array.Empty(); } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs index 570d1a22c..13b351098 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs @@ -58,8 +58,6 @@ public async Task Handle(CompletionParams request, CancellationT int cursorLine = request.Position.Line + 1; int cursorColumn = request.Position.Character + 1; - - ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); try @@ -119,6 +117,12 @@ public async Task Handle(CompletionItem request, CancellationTok return request; } + // No details means the module hasn't been imported yet and Intellisense shouldn't import the module to get this info. + if (request.Detail is null) + { + return request; + } + try { await _completionResolveLock.WaitAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs index 7343c7a17..fda42bf0f 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FoldingRangeHandler.cs @@ -34,7 +34,7 @@ public PsesFoldingRangeHandler(ILoggerFactory factory, ConfigurationService conf public override Task> Handle(FoldingRangeRequestParam request, CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) { _logger.LogDebug("FoldingRange request canceled for file: {0}", request.TextDocument.Uri); return Task.FromResult(new Container()); @@ -57,12 +57,13 @@ public override Task> Handle(FoldingRangeRequestParam re foreach (FoldingReference fold in TokenOperations.FoldableReferences(scriptFile.ScriptTokens).References) { - result.Add(new FoldingRange { - EndCharacter = fold.EndCharacter, - EndLine = fold.EndLine + endLineOffset, - Kind = fold.Kind, + result.Add(new FoldingRange + { + EndCharacter = fold.EndCharacter, + EndLine = fold.EndLine + endLineOffset, + Kind = fold.Kind, StartCharacter = fold.StartCharacter, - StartLine = fold.StartLine + StartLine = fold.StartLine }); } diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs index 67b24fee9..0d6d95766 100644 --- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs @@ -45,7 +45,7 @@ internal class WorkspaceService }; // An array of globs which includes everything. - private static readonly string[] s_psIncludeAllGlob = new [] + private static readonly string[] s_psIncludeAllGlob = new[] { "**/*" }; @@ -192,9 +192,9 @@ public bool TryGetFile(DocumentUri documentUri, out ScriptFile scriptFile) { // List supported schemes here case "file": + case "inmemory": case "untitled": case "vscode-notebook-cell": - case "inmemory": break; default: From e28144861b300eb56ce14cae28e31b28e18e815c Mon Sep 17 00:00:00 2001 From: Darren Kattan <1424395+dkattan@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:43:38 -0500 Subject: [PATCH 29/29] Removing unintentional changes --- PowerShellEditorServices.build.ps1 | 126 ++++++++++-------- build.ps1 | 28 ++-- .../EditorServicesLoader.cs | 2 +- 3 files changed, 84 insertions(+), 72 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index 01b698c9b..3bf93fe33 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -23,9 +23,9 @@ $script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditor $script:IsPreview = [bool]($script:PsesCommonProps.Project.PropertyGroup.VersionSuffix) $script:NetRuntime = @{ - PS7 = 'netcoreapp3.1' - PS72 = 'net6.0' - Desktop = 'net461' + PS7 = 'netcoreapp3.1' + PS72 = 'net6.0' + Desktop = 'net461' Standard = 'netstandard2.0' } @@ -42,11 +42,11 @@ if (Get-Command git -ErrorAction SilentlyContinue) { function Invoke-WithCreateDefaultHook { param([scriptblock]$ScriptBlock) - try { + try + { $env:PSES_TEST_USE_CREATE_DEFAULT = 1 & $ScriptBlock - } - finally { + } finally { Remove-Item env:PSES_TEST_USE_CREATE_DEFAULT } } @@ -69,22 +69,25 @@ function Install-Dotnet { Invoke-WebRequest "https://dot.net/v1/$installScript" -OutFile $installScriptPath # Download and install the different .NET channels - foreach ($dotnetChannel in $Channel) { + foreach ($dotnetChannel in $Channel) + { Write-Host "`n### Installing .NET CLI $Version...`n" if ($script:IsNix) { chmod +x $installScriptPath } - $params = if ($script:IsNix) { + $params = if ($script:IsNix) + { @('-Channel', $dotnetChannel, '-InstallDir', $env:DOTNET_INSTALL_DIR, '-NoPath', '-Verbose') } - else { + else + { @{ - Channel = $dotnetChannel + Channel = $dotnetChannel InstallDir = $env:DOTNET_INSTALL_DIR - NoPath = $true - Verbose = $true + NoPath = $true + Verbose = $true } } @@ -105,12 +108,13 @@ task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServe if (!(Test-Path $dotnetExePath)) { # TODO: Test .NET 5 with PowerShell 7.1 - Install-Dotnet -Channel '3.1', '5.0', '6.0' + Install-Dotnet -Channel '3.1','5.0','6.0' } # This variable is used internally by 'dotnet' to know where it's installed $script:dotnetExe = Resolve-Path $dotnetExePath - if (!$env:DOTNET_INSTALL_DIR) { + if (!$env:DOTNET_INSTALL_DIR) + { $dotnetExeDir = [System.IO.Path]::GetDirectoryName($script:dotnetExe) $env:PATH = $dotnetExeDir + [System.IO.Path]::PathSeparator + $env:PATH $env:DOTNET_INSTALL_DIR = $dotnetExeDir @@ -125,7 +129,7 @@ task BinClean { Remove-Item $PSScriptRoot\module\PowerShellEditorServices.VSCode\bin -Recurse -Force -ErrorAction Ignore } -task Clean BinClean, { +task Clean BinClean,{ exec { & $script:dotnetExe restore } exec { & $script:dotnetExe clean } Get-ChildItem -Recurse $PSScriptRoot\src\*.nupkg | Remove-Item -Force -ErrorAction Ignore @@ -136,9 +140,9 @@ task Clean BinClean, { $moduleJsonPath = "$PSScriptRoot\modules.json" if (Test-Path $moduleJsonPath) { Get-Content -Raw $moduleJsonPath | - ConvertFrom-Json | - ForEach-Object { $_.PSObject.Properties.Name } | - ForEach-Object { Remove-Item -Path "$PSScriptRoot/module/$_" -Recurse -Force -ErrorAction Ignore } + ConvertFrom-Json | + ForEach-Object { $_.PSObject.Properties.Name } | + ForEach-Object { Remove-Item -Path "$PSScriptRoot/module/$_" -Recurse -Force -ErrorAction Ignore } } } @@ -176,11 +180,9 @@ task CreateBuildInfo -Before Build { if ($env:TF_BUILD) { if ($env:BUILD_BUILDNUMBER -like "PR-*") { $buildOrigin = "PR" - } - elseif ($env:BUILD_DEFINITIONNAME -like "*-CI") { + } elseif ($env:BUILD_DEFINITIONNAME -like "*-CI") { $buildOrigin = "CI" - } - else { + } else { $buildOrigin = "Release" } @@ -188,7 +190,8 @@ task CreateBuildInfo -Before Build { $propsBody = $propsXml.Project.PropertyGroup $buildVersion = $propsBody.VersionPrefix - if ($propsBody.VersionSuffix) { + if ($propsBody.VersionSuffix) + { $buildVersion += '-' + $propsBody.VersionSuffix } } @@ -227,15 +230,17 @@ task SetupHelpForTests { Write-Host "Updating help for tests" Update-Help -Module Microsoft.PowerShell.Utility -Force -Scope CurrentUser } - else { + else + { Write-Host "Write-Host help found -- Update-Help skipped" } } -task Build BinClean, { +task Build BinClean,{ exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard } exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 } - if (-not $script:IsNix) { + if (-not $script:IsNix) + { exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop } } @@ -245,12 +250,12 @@ task Build BinClean, { function DotNetTestFilter { # Reference https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests - if ($TestFilter) { @("--filter", $TestFilter) } else { "" } + if ($TestFilter) { @("--filter",$TestFilter) } else { "" } } -task Test SetupHelpForTests, TestServer, TestE2E +task Test SetupHelpForTests,TestServer,TestE2E -task TestServer TestServerWinPS, TestServerPS7, TestServerPS72 +task TestServer TestServerWinPS,TestServerPS7,TestServerPS72 task TestServerWinPS -If (-not $script:IsNix) { Set-Location .\test\PowerShellEditorServices.Test\ @@ -283,8 +288,7 @@ task TestE2E { try { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine); exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } - } - finally { + } finally { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine); } } @@ -299,7 +303,8 @@ task LayoutModule -After Build { $psesCoreHostPath = "$psesBinOutputPath/Core" $psesDeskHostPath = "$psesBinOutputPath/Desktop" - foreach ($dir in $psesDepsPath, $psesCoreHostPath, $psesDeskHostPath, $psesVSCodeBinOutputPath) { + foreach ($dir in $psesDepsPath,$psesCoreHostPath,$psesDeskHostPath,$psesVSCodeBinOutputPath) + { New-Item -Force -Path $dir -ItemType Directory } @@ -312,29 +317,37 @@ task LayoutModule -After Build { [void]$includedDlls.Add('System.Management.Automation.dll') # PSES/bin/Common - foreach ($psesComponent in Get-ChildItem $script:PsesOutput) { + foreach ($psesComponent in Get-ChildItem $script:PsesOutput) + { if ($psesComponent.Name -eq 'System.Management.Automation.dll' -or - $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') { + $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') + { continue } - if ($psesComponent.Extension) { + if ($psesComponent.Extension) + { [void]$includedDlls.Add($psesComponent.Name) Copy-Item -Path $psesComponent.FullName -Destination $psesDepsPath -Force } } # PSES/bin/Core - foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) { - if (-not $includedDlls.Contains($hostComponent.Name)) { + foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) + { + if (-not $includedDlls.Contains($hostComponent.Name)) + { Copy-Item -Path $hostComponent.FullName -Destination $psesCoreHostPath -Force } } # PSES/bin/Desktop - if (-not $script:IsNix) { - foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) { - if (-not $includedDlls.Contains($hostComponent.Name)) { + if (-not $script:IsNix) + { + foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) + { + if (-not $includedDlls.Contains($hostComponent.Name)) + { Copy-Item -Path $hostComponent.FullName -Destination $psesDeskHostPath -Force } } @@ -342,8 +355,10 @@ task LayoutModule -After Build { # Assemble the PowerShellEditorServices.VSCode module - foreach ($vscodeComponent in Get-ChildItem $script:VSCodeOutput) { - if (-not $includedDlls.Contains($vscodeComponent.Name)) { + foreach ($vscodeComponent in Get-ChildItem $script:VSCodeOutput) + { + if (-not $includedDlls.Contains($vscodeComponent.Name)) + { Copy-Item -Path $vscodeComponent.FullName -Destination $psesVSCodeBinOutputPath -Force } } @@ -359,15 +374,16 @@ task RestorePsesModules -After Build { (Get-Content -Raw $ModulesJsonPath | ConvertFrom-Json).PSObject.Properties | ForEach-Object { $name = $_.Name $body = @{ - Name = $name - MinimumVersion = $_.Value.MinimumVersion - MaximumVersion = $_.Value.MaximumVersion + Name = $name + MinimumVersion = $_.Value.MinimumVersion + MaximumVersion = $_.Value.MaximumVersion AllowPrerelease = $script:IsPreview - Repository = if ($_.Value.Repository) { $_.Value.Repository } else { $DefaultModuleRepository } - Path = $submodulePath + Repository = if ($_.Value.Repository) { $_.Value.Repository } else { $DefaultModuleRepository } + Path = $submodulePath } - if (-not $name) { + if (-not $name) + { throw "EditorServices module listed without name in '$ModulesJsonPath'" } @@ -382,8 +398,10 @@ task RestorePsesModules -After Build { } # Save each module in the modules.json file - foreach ($moduleName in $moduleInfos.Keys) { - if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) { + foreach ($moduleName in $moduleInfos.Keys) + { + if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) + { Write-Host "`tModule '${moduleName}' already detected. Skipping" continue } @@ -391,10 +409,10 @@ task RestorePsesModules -After Build { $moduleInstallDetails = $moduleInfos[$moduleName] $splatParameters = @{ - Name = $moduleName - AllowPrerelease = $moduleInstallDetails.AllowPrerelease - Repository = if ($moduleInstallDetails.Repository) { $moduleInstallDetails.Repository } else { $DefaultModuleRepository } - Path = $submodulePath + Name = $moduleName + AllowPrerelease = $moduleInstallDetails.AllowPrerelease + Repository = if ($moduleInstallDetails.Repository) { $moduleInstallDetails.Repository } else { $DefaultModuleRepository } + Path = $submodulePath } # Only add Min and Max version if we're doing a stable release. diff --git a/build.ps1 b/build.ps1 index a16e2925d..8dd89bb13 100644 --- a/build.ps1 +++ b/build.ps1 @@ -18,18 +18,16 @@ param( ) $NeededTools = @{ - OpenSsl = "openssl for macOS" + OpenSsl = "openssl for macOS" PowerShellGet = "PowerShellGet latest" - InvokeBuild = "InvokeBuild latest" + InvokeBuild = "InvokeBuild latest" } if ((-not $PSVersionTable["OS"]) -or $PSVersionTable["OS"].Contains("Windows")) { $OS = "Windows" -} -elseif ($PSVersionTable["OS"].Contains("Darwin")) { +} elseif ($PSVersionTable["OS"].Contains("Darwin")) { $OS = "macOS" -} -else { +} else { $OS = "Linux" } @@ -38,8 +36,7 @@ function needsOpenSsl () { if ($OS -eq "macOS") { try { $opensslVersion = (openssl version) - } - catch { + } catch { return $true } } @@ -85,25 +82,22 @@ if ($Bootstrap) { $missingTools = getMissingTools if (($missingTools).Count -eq 0) { $string += "* nothing!`n`n Run this script without a flag to build or a -Clean to clean." - } - else { - $missingTools | ForEach-Object { $string += "* $_`n" } + } else { + $missingTools | ForEach-Object {$string += "* $_`n"} $string += "`nAll instructions for installing these tools can be found on PowerShell Editor Services' Github:`n" ` + "https://github.com/powershell/PowerShellEditorServices#development" } Write-Host "`n$string`n" -} -elseif (hasMissingTools) { +} elseif(hasMissingTools) { Write-Host "You are missing needed tools. Run './build.ps1 -Bootstrap' to see what they are." -} -else { - if ($Clean) { +} else { + if($Clean) { Invoke-Build Clean } Invoke-Build Build - if ($Test) { + if($Test) { Invoke-Build Test } } \ No newline at end of file diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 0fbb5324a..59956df1a 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -254,7 +254,7 @@ private void UpdatePSModulePath() return; } - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator); + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator); psModulePath = $"{psModulePath}{Path.PathSeparator}{_hostConfig.BundledModulePath}"; Environment.SetEnvironmentVariable("PSModulePath", psModulePath);