From 42173541a54cb0e8e4d461816675b194f9f6445d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 12:26:34 +0000 Subject: [PATCH 1/2] Bump Newtonsoft.Json from 12.0.2 to 13.0.1 Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 12.0.2 to 13.0.1. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/12.0.2...13.0.1) Signed-off-by: dependabot[bot] --- .../PowerShellEditorServices.Test.E2E.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index 2c443e008..af00ee177 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -9,7 +9,7 @@ - + From d1c5e1acdb2f36a9ae83b7824fe7cca92ca85a48 Mon Sep 17 00:00:00 2001 From: dkattan <1424395+dkattan@users.noreply.github.com> Date: Wed, 4 Aug 2021 13:42:48 -0500 Subject: [PATCH 2/2] Centralized Module Loading to PowerShellContextService.cs --- .editorconfig | 27 ++++ .github/CODEOWNERS | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .vsts-ci/azure-pipelines-ci.yml | 57 ++++---- .vsts-ci/azure-pipelines-release.yml | 64 ++++++--- .vsts-ci/misc-analysis.yml | 14 +- .vsts-ci/templates/ci-general.yml | 65 ++++----- .vsts-ci/templates/publish-general.yml | 12 ++ .vsts-ci/templates/release-general.yml | 67 +++++---- PowerShellEditorServices.Common.props | 3 + PowerShellEditorServices.build.ps1 | 39 +----- .../InvokeReadLineForEditorServicesCommand.cs | 3 +- .../EditorServicesLoader.cs | 15 +- .../PowerShellEditorServices.Hosting.csproj | 4 - .../CustomViews/CustomViewBase.cs | 27 ++-- .../CustomViews/HtmlContentView.cs | 35 ++--- .../CustomViews/HtmlContentViewsFeature.cs | 2 +- .../Api/EditorExtensionServiceProvider.cs | 4 +- .../Extensions/Api/EditorUIService.cs | 6 +- .../Extensions/Api/WorkspaceService.cs | 2 +- .../PowerShellEditorServices.csproj | 1 - .../Analysis/PssaCmdletAnalysisEngine.cs | 2 +- .../CodeLens/PesterCodeLensProvider.cs | 2 +- .../CodeLens/ReferencesCodeLensProvider.cs | 2 +- .../DebugAdapter/BreakpointService.cs | 8 +- .../Services/DebugAdapter/DebugService.cs | 12 +- .../Handlers/DisconnectHandler.cs | 2 +- .../Handlers/LaunchAndAttachHandler.cs | 10 +- .../Handlers/StackTraceHandler.cs | 2 +- .../Console/ChoicePromptHandler.cs | 4 +- .../Console/ConsoleReadLine.cs | 42 +++--- .../Console/TerminalInputPromptHandler.cs | 2 +- .../Console/UnixConsoleOperations.cs | 10 +- .../Handlers/GetCommentHelpHandler.cs | 2 +- .../Handlers/GetVersionHandler.cs | 4 +- .../PowerShellContextService.cs | 130 ++++++++++-------- .../RemoteFileManagerService.cs | 6 +- .../Session/Host/EditorServicesPSHost.cs | 2 +- .../Session/InvocationEventQueue.cs | 4 +- .../Session/PSReadLinePromptContext.cs | 82 +++++------ .../PowerShellContext/Session/PromptNest.cs | 16 +-- .../Services/Symbols/SymbolsService.cs | 10 +- .../Services/Symbols/Vistors/AstOperations.cs | 2 +- .../Symbols/Vistors/FindSymbolsVisitor.cs | 2 +- .../Handlers/CompletionHandler.cs | 2 +- .../Handlers/DefinitionHandler.cs | 2 +- .../Handlers/DocumentHighlightHandler.cs | 2 +- .../Handlers/ReferencesHandler.cs | 2 +- .../Handlers/TextDocumentHandler.cs | 2 +- .../Services/TextDocument/TokenOperations.cs | 3 - .../Handlers/WorkspaceSymbolsHandler.cs | 2 +- .../DebugAdapterProtocolMessageTests.cs | 6 +- .../LSPTestsFixures.cs | 2 +- .../LanguageServerProtocolMessageTests.cs | 74 +++++----- .../PowerShellEditorServices.Test.E2E.csproj | 2 +- .../Processes/StdioServerProcess.cs | 2 +- .../TestUtilities/TestUtilities.cs | 2 - .../Language/LanguageServiceTests.cs | 42 +++--- .../Language/TokenOperationsTests.cs | 4 +- .../PowerShellContextFactory.cs | 19 +-- .../Session/PowerShellContextTests.cs | 38 ++--- .../Session/ScriptFileTests.cs | 24 ++-- .../Session/WorkspaceTests.cs | 2 - .../Utility/AsyncLockTests.cs | 3 +- .../Utility/AsyncQueueTests.cs | 13 +- {scripts => tools}/azurePipelinesBuild.ps1 | 10 +- 66 files changed, 529 insertions(+), 538 deletions(-) create mode 100644 .vsts-ci/templates/publish-general.yml rename {scripts => tools}/azurePipelinesBuild.ps1 (76%) diff --git a/.editorconfig b/.editorconfig index e0f9bbf3f..b4753066b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,6 +13,33 @@ trim_trailing_whitespace = true csharp_space_before_open_square_brackets = true csharp_space_after_keywords_in_control_flow_statements = true +# CS0168: The variable 'var' is declared but never used +dotnet_diagnostic.CS0168.severity = error +# CS0169: The private field 'class member' is never used +dotnet_diagnostic.CS0169.severity = error +# CS0219: The variable 'variable' is assigned but its value is never used +dotnet_diagnostic.CS0219.severity = error +# CS0414: The private field 'field' is assigned but its value is never used +dotnet_diagnostic.CS0414.severity = error +# CA1068: CancellationToken parameters must come last +dotnet_diagnostic.CA1068.severity = error +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = error +# CA1823: Avoid unused private fields +dotnet_diagnostic.CA1823.severity = error +# CA2007: Do not directly await a Task +dotnet_diagnostic.CA2007.severity = error +# CA2016: Forward the CancellationToken parameter to methods that take one +dotnet_diagnostic.CA2016.severity = error +# All maintainability issues (dead code etc.) +# See: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/maintainability-warnings +dotnet_analyzer_diagnostic.category-Maintainability.severity = error +# VSTHRD002: Synchronously waiting on tasks or awaiters may cause deadlocks +# TODO: Fix all of these issues and explicitly ignore the intentional ones. +dotnet_diagnostic.VSTHRD002.severity = silent +# VSTHRD200: Use "Async" suffix for awaitable methods +dotnet_diagnostic.VSTHRD200.severity = silent + [*.{json}] indent_size = 2 trim_trailing_whitespace = true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 76be6cf65..4d54b18d7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,7 +1,7 @@ # https://help.github.com/articles/about-codeowners/ # Global reviewers -* @tylerl0706 @rjmholt +* @andschwa @rjmholt # Area: Analysis & Formatting src/PowerShellEditorServices/Analysis/ @rjmholt diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 31d0cd118..cf4227d7a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -37,7 +37,7 @@ jobs: - name: Build shell: pwsh - run: scripts/azurePipelinesBuild.ps1 + run: tools/azurePipelinesBuild.ps1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 diff --git a/.vsts-ci/azure-pipelines-ci.yml b/.vsts-ci/azure-pipelines-ci.yml index d9ff9a82d..25706f2c0 100644 --- a/.vsts-ci/azure-pipelines-ci.yml +++ b/.vsts-ci/azure-pipelines-ci.yml @@ -9,58 +9,49 @@ variables: value: 'true' trigger: - batch: true branches: include: - master - - legacy/1.x - paths: - exclude: - - /.dependabot/* - - /.poshchan/* - - /.github/**/* - - /.vscode/**/* - - /.vsts-ci/misc-analysis.yml - - /tools/**/* - - .editorconfig - - .gitattributes - - .gitignore - - /docs/**/* - - /CHANGELOG.md - - /CONTRIBUTING.md - - /README.md - - /LICENSE - - /CODE_OF_CONDUCT.md -# TODO: Setup matrix of image support. +pr: +- master + jobs: -- job: 'PS51_Win10' - displayName: PowerShell 5.1 | Windows 10 +- job: PS51_Win2016 + displayName: PowerShell 5.1 - Windows Server 2016 + pool: + vmImage: vs2017-win2016 + steps: + - template: templates/ci-general.yml + parameters: + pwsh: false + +- job: PS51_Win2019 + displayName: PowerShell 5.1 - Windows Server 2019 pool: - # TODO: Update this image. - vmImage: 'vs2017-win2016' + vmImage: windows-2019 steps: - template: templates/ci-general.yml parameters: pwsh: false -- job: 'PS7_Win10' - displayName: PowerShell 7 | Windows 10 +- job: PS7_Win2019 + displayName: PowerShell 7 - Windows Server 2019 pool: - vmImage: 'windows-2019' + vmImage: windows-2019 steps: - template: templates/ci-general.yml -- job: 'PS7_macOS' - displayName: PowerShell 7 | macOS +- job: PS7_macOS + displayName: PowerShell 7 - macOS 10.15 pool: - vmImage: 'macOS-10.15' + vmImage: macOS-10.15 steps: - template: templates/ci-general.yml -- job: 'PS7_Ubuntu' - displayName: PowerShell 7 | Ubuntu +- job: PS7_Ubuntu + displayName: PowerShell 7 - Ubuntu 20.04 pool: - vmImage: 'ubuntu-20.04' + vmImage: ubuntu-20.04 steps: - template: templates/ci-general.yml diff --git a/.vsts-ci/azure-pipelines-release.yml b/.vsts-ci/azure-pipelines-release.yml index 4b861a570..e3e1d934a 100644 --- a/.vsts-ci/azure-pipelines-release.yml +++ b/.vsts-ci/azure-pipelines-release.yml @@ -1,3 +1,5 @@ +name: Release-$(Build.SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.rr) + variables: # Don't download unneeded packages - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE @@ -9,33 +11,51 @@ variables: trigger: branches: include: - - release/* - tags: - include: - - v* + - release resources: repositories: - repository: ComplianceRepo type: github - endpoint: ComplianceGHRepo + endpoint: GitHub name: PowerShell/compliance + - repository: vscode-powershell + type: git + name: vscode-powershell + +stages: +- stage: Build + displayName: Build the release + jobs: + - job: Build + pool: + vmImage: windows-2019 + steps: + - template: templates/ci-general.yml -jobs: -- job: 'ReleaseBuild' - displayName: 'Build release' - pool: - vmImage: 'vs2017-win2016' - steps: - - template: templates/ci-general.yml +- stage: Sign + displayName: Sign the release + jobs: + - job: Sign + pool: + name: 1ES + demands: ImageOverride -equals MMS2019 + variables: + - group: ESRP + steps: + - template: templates/release-general.yml -- job: 'SignBuild' - displayName: Signing Build - dependsOn: 'ReleaseBuild' - pool: - name: '1ES' - demands: ImageOverride -equals MMS2019 - variables: - - group: ESRP - steps: - - template: templates/release-general.yml +- stage: Publish + displayName: Publish the draft release + jobs: + - deployment: Publish + environment: PowerShellEditorServices + pool: + vmImage: ubuntu-latest + variables: + - group: Publish + strategy: + runOnce: + deploy: + steps: + - template: templates/publish-general.yml diff --git a/.vsts-ci/misc-analysis.yml b/.vsts-ci/misc-analysis.yml index 1c229a7ae..2647eb182 100644 --- a/.vsts-ci/misc-analysis.yml +++ b/.vsts-ci/misc-analysis.yml @@ -1,31 +1,25 @@ name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) + trigger: - # Batch merge builds together while a merge build is running - batch: true branches: include: - master pr: - branches: - include: - - master - - legacy/1.x +- master resources: repositories: - repository: ComplianceRepo type: github - endpoint: ComplianceGHRepo + endpoint: GitHub name: PowerShell/compliance jobs: -- job: Compliance_Job +- job: Compliance pool: vmImage: windows-latest steps: - checkout: self - clean: true - checkout: ComplianceRepo - clean: true - template: ci-compliance.yml@ComplianceRepo diff --git a/.vsts-ci/templates/ci-general.yml b/.vsts-ci/templates/ci-general.yml index 34b81b7c1..016b340dc 100644 --- a/.vsts-ci/templates/ci-general.yml +++ b/.vsts-ci/templates/ci-general.yml @@ -1,43 +1,36 @@ parameters: - pwsh: true +- name: pwsh + type: boolean + default: true steps: - - powershell: | - Write-Host "Installing PowerShell Daily..." +- pwsh: $PSVersionTable + displayName: PowerShell version - # Use `AGENT_TEMPDIRECTORY` to make sure the downloaded PowerShell is cleaned up. - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://aka.ms/install-powershell.ps1 -OutFile ./install-powershell.ps1 +- task: PowerShell@2 + displayName: Build and test + inputs: + filePath: tools/azurePipelinesBuild.ps1 + pwsh: ${{ parameters.pwsh }} - ./install-powershell.ps1 -Destination $powerShellPath -Daily +# NOTE: We zip the artifacts because they're ~20 MB compressed, but ~300 MB raw, +# and we have limited pipeline artifact storage space. +- task: ArchiveFiles@2 + displayName: Zip pipeline artifacts + inputs: + rootFolderOrFile: module + includeRootFolder: false + archiveType: zip + archiveFile: PowerShellEditorServices-Build.zip + verbose: true - # Using `prependpath` to update the PATH just for this build. - Write-Host "##vso[task.prependpath]$powerShellPath" - displayName: Install PowerShell Daily - continueOnError: true +- publish: PowerShellEditorServices-Build.zip + artifact: PowerShellEditorServices-Build-$(System.JobId) + displayName: Publish unsigned pipeline artifacts - - pwsh: '$PSVersionTable' - displayName: Display PowerShell version information - - - pwsh: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" - displayName: Set Build Name for Non-PR - condition: ne(variables['Build.Reason'], 'PullRequest') - - task: PowerShell@2 - inputs: - filePath: scripts/azurePipelinesBuild.ps1 - pwsh: ${{ parameters.pwsh }} - - task: PublishTestResults@2 - inputs: - testRunner: VSTest - testResultsFiles: '**/*.trx' - condition: succeededOrFailed() - - task: PublishTestResults@2 - inputs: - testRunner: NUnit - testResultsFiles: '**/TestResults.xml' - condition: succeededOrFailed() - - task: PublishBuildArtifacts@1 - inputs: - ArtifactName: PowerShellEditorServices-CI - PathtoPublish: '$(Build.ArtifactStagingDirectory)' - condition: succeededOrFailed() +- task: PublishTestResults@2 + displayName: Publish test results + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' + condition: succeededOrFailed() diff --git a/.vsts-ci/templates/publish-general.yml b/.vsts-ci/templates/publish-general.yml new file mode 100644 index 000000000..cb26033b3 --- /dev/null +++ b/.vsts-ci/templates/publish-general.yml @@ -0,0 +1,12 @@ +steps: +- checkout: self +- checkout: vscode-powershell + +- download: current + artifact: PowerShellEditorServices + displayName: Download signed pipeline artifacts + +- pwsh: | + $(Build.SourcesDirectory)/vscode-powershell/tools/setupReleaseTools.ps1 -Token $(GitHubToken) + New-DraftRelease -RepositoryName PowerShellEditorServices -Assets $(Pipeline.Workspace)/PowerShellEditorServices/PowerShellEditorServices.zip + displayName: Drafting a GitHub Release diff --git a/.vsts-ci/templates/release-general.yml b/.vsts-ci/templates/release-general.yml index 9a9ec2029..7ef4e1479 100644 --- a/.vsts-ci/templates/release-general.yml +++ b/.vsts-ci/templates/release-general.yml @@ -1,27 +1,26 @@ steps: - -- task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific +- download: current + displayName: Download unsigned pipeline artifacts - task: ExtractFiles@1 - displayName: 'Extract Build Zip' + displayName: Extract unsigned artifacts inputs: - archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices-CI/PowerShellEditorServices*.zip' - destinationFolder: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices' + archiveFilePatterns: $(Pipeline.Workspace)/PowerShellEditorServices-Build-*/PowerShellEditorServices-Build.zip + destinationFolder: $(Pipeline.Workspace)/Unsigned + cleanDestinationFolder: true - checkout: ComplianceRepo - displayName: 'Checkout the ComplianceRepo' +# NOTE: The signing templates explicitly copy everything along as they run, so +# the last output path has every signed (and intentionally unsigned) file. - template: EsrpSign.yml@ComplianceRepo parameters: - buildOutputPath: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices' - signOutputPath: '$(Build.ArtifactStagingDirectory)/FirstPartySigned' - alwaysCopy: true # So publishing works - certificateId: 'CP-230012' # Authenticode certificate - useMinimatch: true # This enables the use of globbing + buildOutputPath: $(Pipeline.Workspace)/Unsigned + signOutputPath: $(Pipeline.Workspace)/FirstPartySigned + alwaysCopy: true + certificateId: CP-230012 # Authenticode certificate shouldSign: true # We always want to sign + useMinimatch: true # This enables the use of globbing pattern: | # PowerShellEditorServices Script PowerShellEditorServices/*.{ps1,psd1,psm1,ps1xml} @@ -35,12 +34,12 @@ steps: - template: EsrpSign.yml@ComplianceRepo parameters: - buildOutputPath: '$(Build.ArtifactStagingDirectory)/FirstPartySigned' - signOutputPath: '$(Build.ArtifactStagingDirectory)/ThirdPartySigned' - alwaysCopy: true # So publishing works - certificateId: 'CP-231522' # Third-party certificate - useMinimatch: true # This enables the use of globbing + buildOutputPath: $(Pipeline.Workspace)/FirstPartySigned + signOutputPath: $(Pipeline.Workspace)/ThirdPartySigned + alwaysCopy: true + certificateId: CP-231522 # Third-party certificate shouldSign: true # We always want to sign + useMinimatch: true # This enables the use of globbing pattern: | **/MediatR.dll **/Nerdbank.Streams.dll @@ -49,27 +48,37 @@ steps: **/Serilog*.dll **/UnixConsoleEcho.dll -- publish: $(Build.ArtifactStagingDirectory)/ThirdPartySigned - artifact: PowerShellEditorServices - displayName: 'Publish signed (and unsigned) artifacts' +- task: ArchiveFiles@2 + displayName: Zip signed artifacts + inputs: + rootFolderOrFile: $(Pipeline.Workspace)/ThirdPartySigned + includeRootFolder: false + archiveType: zip + archiveFile: PowerShellEditorServices.zip + replaceExistingArchive: true + verbose: true - checkout: self - template: assembly-module-compliance.yml@ComplianceRepo parameters: # binskim - AnalyzeTarget: '$(Build.ArtifactStagingDirectory)/*.dll' + AnalyzeTarget: $(Pipeline.Workspace)/*.dll AnalyzeSymPath: 'SRV*' # component-governance - sourceScanPath: '$(Build.SourcesDirectory)/PowerShellEditorServices' + sourceScanPath: $(Build.SourcesDirectory)/PowerShellEditorServices # credscan suppressionsFile: '' # TermCheck AKA PoliCheck - targetArgument: '$(Build.SourcesDirectory)/PowerShellEditorServices' - optionsUEPATH: '$(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/UserExclusions.xml' + targetArgument: $(Build.SourcesDirectory)/PowerShellEditorServices + optionsUEPATH: $(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/UserExclusions.xml optionsRulesDBPath: '' - optionsFTPath: '$(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/FileTypeSet.xml' + optionsFTPath: $(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/FileTypeSet.xml # tsa-upload - codeBaseName: 'PowerShell_PowerShellEditorServices_20210201' - # selections + codeBaseName: PowerShell_PowerShellEditorServices_20210201 + # We don't use any Windows APIs directly, so we don't need API scan APIScan: false + +- publish: PowerShellEditorServices.zip + artifact: PowerShellEditorServices + displayName: Publish signed pipeline artifacts diff --git a/PowerShellEditorServices.Common.props b/PowerShellEditorServices.Common.props index ea41c7b43..59da7d55c 100644 --- a/PowerShellEditorServices.Common.props +++ b/PowerShellEditorServices.Common.props @@ -11,5 +11,8 @@ git https://github.com/PowerShell/PowerShellEditorServices portable + + true + diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index fbd126708..60274440e 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -146,31 +146,6 @@ task Clean BinClean,{ } } -task GetProductVersion -Before PackageModule, UploadArtifacts { - [xml]$props = Get-Content .\PowerShellEditorServices.Common.props - - $script:BuildNumber = 9999 - $script:VersionSuffix = $props.Project.PropertyGroup.VersionSuffix - - if ($env:TF_BUILD) { - # SYSTEM_PHASENAME is the Job name. - # Job names can only include `_` but that's not a valid character for versions. - $jobname = $env:SYSTEM_PHASENAME -replace '_', '' - $script:BuildNumber = "$jobname-$env:BUILD_BUILDID" - } - - if ($script:VersionSuffix -ne $null) { - $script:VersionSuffix = "$script:VersionSuffix-$script:BuildNumber" - } - else { - $script:VersionSuffix = "$script:BuildNumber" - } - - $script:FullVersion = "$($props.Project.PropertyGroup.VersionPrefix)-$script:VersionSuffix" - - Write-Host "`n### Product Version: $script:FullVersion`n" -ForegroundColor Green -} - task CreateBuildInfo -Before Build { $buildVersion = "" $buildOrigin = "Development" @@ -435,17 +410,5 @@ task BuildCmdletHelp { New-ExternalHelp -Path $PSScriptRoot\module\PowerShellEditorServices.VSCode\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices.VSCode\en-US -Force } -task PackageModule { - [System.IO.Compression.ZipFile]::CreateFromDirectory( - "$PSScriptRoot/module/", - "$PSScriptRoot/PowerShellEditorServices-$($script:FullVersion).zip", - [System.IO.Compression.CompressionLevel]::Optimal, - $false) -} - -task UploadArtifacts -If ($null -ne $env:TF_BUILD) { - Copy-Item -Path .\PowerShellEditorServices-$($script:FullVersion).zip -Destination $env:BUILD_ARTIFACTSTAGINGDIRECTORY -Force -} - # The default task is to run the entire CI build -task . GetProductVersion, Clean, Build, Test, BuildCmdletHelp, PackageModule, UploadArtifacts +task . Clean, Build, Test, BuildCmdletHelp diff --git a/src/PowerShellEditorServices.Hosting/Commands/InvokeReadLineForEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/InvokeReadLineForEditorServicesCommand.cs index b0adf6fc8..0cfa675d3 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/InvokeReadLineForEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/InvokeReadLineForEditorServicesCommand.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Linq; using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Reflection; @@ -24,7 +25,7 @@ private delegate string ReadLineInvoker( Type type = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2"); MethodInfo method = type?.GetMethod( "ReadLine", - new[] { typeof(Runspace), typeof(EngineIntrinsics), typeof(CancellationToken) }); + new [] { typeof(Runspace), typeof(EngineIntrinsics), typeof(CancellationToken) }); // TODO: Handle method being null here. This shouldn't ever happen. diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 59956df1a..10b7281af 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading.Tasks; @@ -93,7 +94,11 @@ public static EditorServicesLoader Create( AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext defaultLoadContext, AssemblyName asmName) => { +#if DEBUG + logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {asmName}. Stacktrace:\n{new StackTrace()}"); +#else logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {asmName}"); +#endif // We only want the Editor Services DLL; the new ALC will lazily load its dependencies automatically if (!string.Equals(asmName.Name, "Microsoft.PowerShell.EditorServices", StringComparison.Ordinal)) @@ -124,7 +129,11 @@ public static EditorServicesLoader Create( // Unlike in .NET Core, we need to be look for all dependencies in .NET Framework, not just PSES.dll AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => { +#if DEBUG + logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {args.Name}. Stacktrace:\n{new StackTrace()}"); +#else logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {args.Name}"); +#endif var asmName = new AssemblyName(args.Name); var dllName = $"{asmName.Name}.dll"; @@ -217,7 +226,7 @@ public void Dispose() // This is not high priority, since the PSES process shouldn't be reused } - private void LoadEditorServices() + private static void LoadEditorServices() { // This must be in its own method, since the actual load happens when the calling method is called // The call within this method is therefore a total no-op @@ -308,7 +317,7 @@ private void LogHostInformation() LogOperatingSystemDetails(); } - private string GetPSOutputEncoding() + private static string GetPSOutputEncoding() { using (var pwsh = SMA.PowerShell.Create()) { @@ -337,7 +346,7 @@ private void LogOperatingSystemDetails() "); } - private string GetOSArchitecture() + private static string GetOSArchitecture() { #if CoreCLR if (Environment.OSVersion.Platform != PlatformID.Win32NT) diff --git a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj index 16ab98595..58d4fa85c 100644 --- a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj +++ b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj @@ -31,10 +31,6 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/PowerShellEditorServices.VSCode/CustomViews/CustomViewBase.cs b/src/PowerShellEditorServices.VSCode/CustomViews/CustomViewBase.cs index af154d105..b0cc81605 100644 --- a/src/PowerShellEditorServices.VSCode/CustomViews/CustomViewBase.cs +++ b/src/PowerShellEditorServices.VSCode/CustomViews/CustomViewBase.cs @@ -28,40 +28,31 @@ public CustomViewBase( this.languageServer = languageServer; } - internal async Task CreateAsync() - { - await languageServer.SendRequestAsync( + internal Task CreateAsync() => + languageServer.SendRequestAsync( NewCustomViewRequest.Method, new NewCustomViewRequest { Id = this.Id, Title = this.Title, ViewType = this.ViewType, - } - ); - } + }); - public async Task Show(ViewColumn viewColumn) - { - await languageServer.SendRequestAsync( + public Task Show(ViewColumn viewColumn) => + languageServer.SendRequestAsync( ShowCustomViewRequest.Method, new ShowCustomViewRequest { Id = this.Id, ViewColumn = viewColumn - } - ); - } + }); - public async Task Close() - { - await languageServer.SendRequestAsync( + public Task Close() => + languageServer.SendRequestAsync( CloseCustomViewRequest.Method, new CloseCustomViewRequest { Id = this.Id, - } - ); - } + }); } } diff --git a/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentView.cs b/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentView.cs index dcac2ba44..ca3e53ad6 100644 --- a/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentView.cs +++ b/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentView.cs @@ -21,9 +21,8 @@ public HtmlContentView( { } - public async Task SetContentAsync(string htmlBodyContent) - { - await languageServer.SendRequestAsync( + public Task SetContentAsync(string htmlBodyContent) => + languageServer.SendRequestAsync( SetHtmlContentViewRequest.Method, new SetHtmlContentViewRequest { @@ -31,31 +30,24 @@ await languageServer.SendRequestAsync( HtmlContent = new HtmlContent { BodyContent = htmlBodyContent } } ); - } - - public async Task SetContentAsync(HtmlContent htmlContent) - { - HtmlContent validatedContent = - new HtmlContent() - { - BodyContent = htmlContent.BodyContent, - JavaScriptPaths = this.GetUriPaths(htmlContent.JavaScriptPaths), - StyleSheetPaths = this.GetUriPaths(htmlContent.StyleSheetPaths) - }; - await languageServer.SendRequestAsync( + public Task SetContentAsync(HtmlContent htmlContent) => + languageServer.SendRequestAsync( SetHtmlContentViewRequest.Method, new SetHtmlContentViewRequest { Id = this.Id, - HtmlContent = validatedContent + HtmlContent = new HtmlContent() + { + BodyContent = htmlContent.BodyContent, + JavaScriptPaths = HtmlContentView.GetUriPaths(htmlContent.JavaScriptPaths), + StyleSheetPaths = HtmlContentView.GetUriPaths(htmlContent.StyleSheetPaths) + } } ); - } - public async Task AppendContentAsync(string appendedHtmlBodyContent) - { - await languageServer.SendRequestAsync( + public Task AppendContentAsync(string appendedHtmlBodyContent) => + languageServer.SendRequestAsync( AppendHtmlContentViewRequest.Method, new AppendHtmlContentViewRequest { @@ -63,9 +55,8 @@ await languageServer.SendRequestAsync( AppendedHtmlBodyContent = appendedHtmlBodyContent } ); - } - private string[] GetUriPaths(string[] filePaths) + private static string[] GetUriPaths(string[] filePaths) { return filePaths? diff --git a/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentViewsFeature.cs b/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentViewsFeature.cs index df8ac001d..dfdf5e3cb 100644 --- a/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentViewsFeature.cs +++ b/src/PowerShellEditorServices.VSCode/CustomViews/HtmlContentViewsFeature.cs @@ -21,7 +21,7 @@ public async Task CreateHtmlContentViewAsync(string viewTitle) viewTitle, languageServer); - await htmlView.CreateAsync(); + await htmlView.CreateAsync().ConfigureAwait(false); this.AddView(htmlView); return htmlView; diff --git a/src/PowerShellEditorServices/Extensions/Api/EditorExtensionServiceProvider.cs b/src/PowerShellEditorServices/Extensions/Api/EditorExtensionServiceProvider.cs index 661797f1d..8d25db01d 100644 --- a/src/PowerShellEditorServices/Extensions/Api/EditorExtensionServiceProvider.cs +++ b/src/PowerShellEditorServices/Extensions/Api/EditorExtensionServiceProvider.cs @@ -156,7 +156,7 @@ public object GetService(Type serviceType) /// In .NET Framework, this returns null. /// /// The assembly load context used for loading PSES, or null in .NET Framework. - public object GetPsesAssemblyLoadContext() + public static object GetPsesAssemblyLoadContext() { if (!VersionUtils.IsNetCore) { @@ -172,7 +172,7 @@ public object GetPsesAssemblyLoadContext() /// /// The absolute path of the assembly to load. /// The loaded assembly object. - public Assembly LoadAssemblyInPsesLoadContext(string assemblyPath) + public static Assembly LoadAssemblyInPsesLoadContext(string assemblyPath) { if (!VersionUtils.IsNetCore) { diff --git a/src/PowerShellEditorServices/Extensions/Api/EditorUIService.cs b/src/PowerShellEditorServices/Extensions/Api/EditorUIService.cs index 0ab4fe497..f83dd7d20 100644 --- a/src/PowerShellEditorServices/Extensions/Api/EditorUIService.cs +++ b/src/PowerShellEditorServices/Extensions/Api/EditorUIService.cs @@ -116,7 +116,7 @@ public async Task PromptInputAsync(string message) new ShowInputPromptRequest { Name = message, - }).Returning(CancellationToken.None); + }).Returning(CancellationToken.None).ConfigureAwait(false); if (response.PromptCancelled) { @@ -142,7 +142,7 @@ public async Task> PromptMultipleSelectionAsync(string mes Message = message, Choices = choiceDetails, DefaultChoices = defaultChoiceIndexes?.ToArray(), - }).Returning(CancellationToken.None); + }).Returning(CancellationToken.None).ConfigureAwait(false); if (response.PromptCancelled) { @@ -168,7 +168,7 @@ public async Task PromptSelectionAsync(string message, IReadOnlyList -1 ? new[] { defaultChoiceIndex } : null, - }).Returning(CancellationToken.None); + }).Returning(CancellationToken.None).ConfigureAwait(false); if (response.PromptCancelled) { diff --git a/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs b/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs index 3d2dabf7f..98eb9f06e 100644 --- a/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Extensions/Api/WorkspaceService.cs @@ -147,7 +147,7 @@ public IReadOnlyList GetOpenedFiles() return files.AsReadOnly(); } - private IEditorScriptFile GetEditorFileFromScriptFile(ScriptFile file) + private static IEditorScriptFile GetEditorFileFromScriptFile(ScriptFile file) { return new EditorScriptFile(file); } diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 5c5a7c928..562239ded 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -1,5 +1,4 @@  - diff --git a/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs b/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs index b842193c7..70b671e54 100644 --- a/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs +++ b/src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs @@ -362,7 +362,7 @@ private PowerShellResult InvokePowerShell(PSCommand command) /// /// The PowerShell instance to execute. /// The output of PowerShell execution. - private Collection InvokePowerShellWithModulePathPreservation(System.Management.Automation.PowerShell powershell) + private static Collection InvokePowerShellWithModulePathPreservation(System.Management.Automation.PowerShell powershell) { using (PSModulePathPreserver.Take()) { diff --git a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs index e7d0217c9..dd0ef0d1b 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs @@ -42,7 +42,7 @@ public PesterCodeLensProvider(ConfigurationService configurationService) /// The Pester symbol to get CodeLenses for. /// The script file the Pester symbol comes from. /// All CodeLenses for the given Pester symbol. - private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile scriptFile) + private static CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile scriptFile) { string word = pesterSymbol.Command == PesterCommandType.It ? "test" : "tests"; var codeLensResults = new CodeLens[] diff --git a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs index 2964770d6..84119ee81 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs @@ -86,7 +86,7 @@ public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) ScriptFile[] references = _workspaceService.ExpandScriptReferences( scriptFile); - SymbolReference foundSymbol = _symbolsService.FindFunctionDefinitionAtLocation( + SymbolReference foundSymbol = SymbolsService.FindFunctionDefinitionAtLocation( scriptFile, codeLens.Range.Start.Line + 1, codeLens.Range.Start.Character + 1); diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs index 3f6bf2bf8..ab49bd21a 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs @@ -47,7 +47,7 @@ public async Task> GetBreakpointsAsync() // Legacy behavior PSCommand psCommand = new PSCommand(); psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); - IEnumerable breakpoints = await _powerShellContextService.ExecuteCommandAsync(psCommand); + IEnumerable breakpoints = await _powerShellContextService.ExecuteCommandAsync(psCommand).ConfigureAwait(false); return breakpoints.ToList(); } @@ -133,7 +133,7 @@ public async Task> SetBreakpointsAsync(string esc if (psCommand != null) { IEnumerable setBreakpoints = - await _powerShellContextService.ExecuteCommandAsync(psCommand); + await _powerShellContextService.ExecuteCommandAsync(psCommand).ConfigureAwait(false); configuredBreakpoints.AddRange( setBreakpoints.Select(BreakpointDetails.Create)); } @@ -210,7 +210,7 @@ public async Task> SetCommandBreakpoints(I if (psCommand != null) { IEnumerable setBreakpoints = - await _powerShellContextService.ExecuteCommandAsync(psCommand); + await _powerShellContextService.ExecuteCommandAsync(psCommand).ConfigureAwait(false); configuredBreakpoints.AddRange( setBreakpoints.Select(CommandBreakpointDetails.Create)); } @@ -301,7 +301,7 @@ public async Task RemoveBreakpointsAsync(IEnumerable breakpoints) psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint"); psCommand.AddParameter("Id", breakpoints.Select(b => b.Id).ToArray()); - await _powerShellContextService.ExecuteCommandAsync(psCommand); + await _powerShellContextService.ExecuteCommandAsync(psCommand).ConfigureAwait(false); } } diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs index ff2773c28..92a4350a1 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs @@ -43,8 +43,6 @@ internal class DebugService private StackFrameDetails[] stackFrameDetails; private readonly PropertyInfo invocationTypeScriptPositionProperty; - private static int breakpointHitCounter; - private readonly SemaphoreSlim debugInfoHandle = AsyncUtils.CreateSimpleLockingSemaphore(); #endregion @@ -190,7 +188,7 @@ public async Task SetLineBreakpointsAsync( return await dscBreakpoints.SetLineBreakpointsAsync( this.powerShellContext, escapedScriptPath, - breakpoints); + breakpoints).ConfigureAwait(false); } /// @@ -208,7 +206,9 @@ public async Task SetCommandBreakpointsAsync( if (clearExisting) { // Flatten dictionary values into one list and remove them all. - await _breakpointService.RemoveBreakpointsAsync((await _breakpointService.GetBreakpointsAsync()).Where( i => i is CommandBreakpoint)).ConfigureAwait(false); + await _breakpointService.RemoveBreakpointsAsync( + (await _breakpointService.GetBreakpointsAsync().ConfigureAwait(false)) + .Where( i => i is CommandBreakpoint)).ConfigureAwait(false); } if (breakpoints.Length > 0) @@ -854,7 +854,7 @@ private async Task FetchStackFramesAsync(string scriptNameOverride) } } - private string TrimScriptListingLine(PSObject scriptLineObj, ref int prefixLength) + private static string TrimScriptListingLine(PSObject scriptLineObj, ref int prefixLength) { string scriptLine = scriptLineObj.ToString(); @@ -906,7 +906,7 @@ await this.powerShellContext.ExecuteCommandAsync( string.Join( Environment.NewLine, scriptListingLines - .Select(o => this.TrimScriptListingLine(o, ref linePrefixLength)) + .Select(o => DebugService.TrimScriptListingLine(o, ref linePrefixLength)) .Where(s => s != null)); this.temporaryScriptListingPath = diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs index 579685ac8..9fa9c3e65 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs @@ -75,7 +75,7 @@ public async Task Handle(DisconnectArguments request, Cancel #pragma warning disable CS4014 // Trigger the clean up of the debugger. No need to wait for it. - Task.Run(_psesDebugServer.OnSessionEnded); + Task.Run(_psesDebugServer.OnSessionEnded, cancellationToken); #pragma warning restore CS4014 return new DisconnectResponse(); diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs index ebce7e39d..51581c968 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs @@ -264,7 +264,7 @@ await _powerShellContextService.ExecuteScriptStringAsync( await _powerShellContextService.ExecuteScriptStringAsync( $"Enter-PSHostProcess -Id {processId}", - errorMessages); + errorMessages).ConfigureAwait(false); if (errorMessages.Length > 0) { @@ -280,7 +280,7 @@ await _powerShellContextService.ExecuteScriptStringAsync( await _powerShellContextService.ExecuteScriptStringAsync( $"Enter-PSHostProcess -CustomPipeName {request.CustomPipeName}", - errorMessages); + errorMessages).ConfigureAwait(false); if (errorMessages.Length > 0) { @@ -307,7 +307,7 @@ await _powerShellContextService.ExecuteScriptStringAsync( .AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace") .AddParameter("Name", request.RunspaceName) .AddCommand("Microsoft.PowerShell.Utility\\Select-Object") - .AddParameter("ExpandProperty", "Id")); + .AddParameter("ExpandProperty", "Id")).ConfigureAwait(false); foreach (var id in ids) { _debugStateService.RunspaceId = id; @@ -396,12 +396,12 @@ private async Task OnExecutionCompletedAsync(Task executeTask) { try { - await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSHostProcess"); + await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSHostProcess").ConfigureAwait(false); if (_debugStateService.IsRemoteAttach && _powerShellContextService.CurrentRunspace.Location == RunspaceLocation.Remote) { - await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSSession"); + await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSSession").ConfigureAwait(false); } } catch (Exception e) diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs index a55b02640..919bc0df3 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs @@ -30,7 +30,7 @@ public StackTraceHandler( public Task Handle(StackTraceArguments request, CancellationToken cancellationToken) { StackFrameDetails[] stackFrameDetails = - _debugService.GetStackFrames(); + _debugService.GetStackFrames(cancellationToken); // Handle a rare race condition where the adapter requests stack frames before they've // begun building. diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Console/ChoicePromptHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Console/ChoicePromptHandler.cs index a284fa49c..499a757a1 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Console/ChoicePromptHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Console/ChoicePromptHandler.cs @@ -144,7 +144,7 @@ public Task PromptForChoiceAsync( throw new TaskCanceledException(task); } - return this.GetSingleResult(task.GetAwaiter().GetResult()); + return ChoicePromptHandler.GetSingleResult(task.GetAwaiter().GetResult()); })); } @@ -335,7 +335,7 @@ protected override void OnPromptCancelled() #region Private Methods - private int GetSingleResult(int[] choiceArray) + private static int GetSingleResult(int[] choiceArray) { return choiceArray != null diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Console/ConsoleReadLine.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Console/ConsoleReadLine.cs index 3223eb1d0..8e51b3133 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Console/ConsoleReadLine.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Console/ConsoleReadLine.cs @@ -42,7 +42,7 @@ public Task ReadSimpleLineAsync(CancellationToken cancellationToken) return this.ReadLineAsync(false, cancellationToken); } - public async Task ReadSecureLineAsync(CancellationToken cancellationToken) + public async static Task ReadSecureLineAsync(CancellationToken cancellationToken) { SecureString secureString = new SecureString(); @@ -216,7 +216,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel } else { - using (RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandleAsync().ConfigureAwait(false)) + using (RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandleAsync(cancellationToken) .ConfigureAwait(false)) using (PowerShell powerShell = PowerShell.Create()) { powerShell.Runspace = runspaceHandle.Runspace; @@ -253,7 +253,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (completion != null) { currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -271,7 +271,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (currentCursorIndex > 0) { currentCursorIndex = - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -283,7 +283,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel currentCompletion = null; currentCursorIndex = - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -296,7 +296,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (currentCursorIndex < inputLine.Length) { currentCursorIndex = - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -308,7 +308,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel currentCompletion = null; currentCursorIndex = - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -342,7 +342,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel historyIndex--; currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -367,7 +367,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (historyIndex < currentHistory.Count) { currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -379,7 +379,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel else if (historyIndex == currentHistory.Count) { currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -396,7 +396,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel historyIndex = currentHistory != null ? currentHistory.Count : -1; currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -412,7 +412,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (currentCursorIndex > 0) { currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -430,7 +430,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel if (currentCursorIndex < inputLine.Length) { currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -471,7 +471,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel currentCompletion = null; currentCursorIndex = - this.InsertInput( + ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, @@ -490,7 +490,7 @@ internal async Task InvokeLegacyReadLineAsync(bool isCommandLine, Cancel } // TODO: Is this used? - private int CalculateIndexFromCursor( + private static int CalculateIndexFromCursor( int promptStartCol, int promptStartRow, int consoleWidth) @@ -500,7 +500,7 @@ private int CalculateIndexFromCursor( ConsoleProxy.GetCursorLeft() - promptStartCol; } - private void CalculateCursorFromIndex( + private static void CalculateCursorFromIndex( int promptStartCol, int promptStartRow, int consoleWidth, @@ -513,7 +513,7 @@ private void CalculateCursorFromIndex( cursorCol = cursorCol % consoleWidth; } - private int InsertInput( + private static int InsertInput( StringBuilder inputLine, int promptStartCol, int promptStartRow, @@ -532,7 +532,7 @@ private int InsertInput( } // Move the cursor to the new insertion point - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -581,7 +581,7 @@ private int InsertInput( { // Move the cursor to the final position return - this.MoveCursorToIndex( + ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, @@ -593,13 +593,13 @@ private int InsertInput( } } - private int MoveCursorToIndex( + private static int MoveCursorToIndex( int promptStartCol, int promptStartRow, int consoleWidth, int newCursorIndex) { - this.CalculateCursorFromIndex( + ConsoleReadLine.CalculateCursorFromIndex( promptStartCol, promptStartRow, consoleWidth, diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Console/TerminalInputPromptHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Console/TerminalInputPromptHandler.cs index 151ea9a88..a9d07c03f 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Console/TerminalInputPromptHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Console/TerminalInputPromptHandler.cs @@ -66,7 +66,7 @@ protected override async Task ReadInputStringAsync(CancellationToken can /// A Task that can be awaited to get the user's response. protected override async Task ReadSecureStringAsync(CancellationToken cancellationToken) { - SecureString secureString = await this.consoleReadLine.ReadSecureLineAsync(cancellationToken).ConfigureAwait(false); + SecureString secureString = await ConsoleReadLine.ReadSecureLineAsync(cancellationToken).ConfigureAwait(false); this.hostOutput.WriteOutput(string.Empty); return secureString; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Console/UnixConsoleOperations.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Console/UnixConsoleOperations.cs index 8ed801ea5..18bb3063a 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Console/UnixConsoleOperations.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Console/UnixConsoleOperations.cs @@ -243,7 +243,7 @@ private async Task ShortWaitForKeyAsync(CancellationToken cancellationToke return false; } - private bool SpinUntilKeyAvailable(int millisecondsTimeout, CancellationToken cancellationToken) + private static bool SpinUntilKeyAvailable(int millisecondsTimeout, CancellationToken cancellationToken) { return SpinWait.SpinUntil( () => @@ -254,7 +254,7 @@ private bool SpinUntilKeyAvailable(int millisecondsTimeout, CancellationToken ca millisecondsTimeout); } - private Task SpinUntilKeyAvailableAsync(int millisecondsTimeout, CancellationToken cancellationToken) + private static Task SpinUntilKeyAvailableAsync(int millisecondsTimeout, CancellationToken cancellationToken) { return Task.Factory.StartNew( () => SpinWait.SpinUntil( @@ -264,10 +264,10 @@ private Task SpinUntilKeyAvailableAsync(int millisecondsTimeout, Cancellat s_waitHandle.Wait(ShortWaitForKeySpinUntilSleepTime, cancellationToken); return IsKeyAvailable(cancellationToken); }, - millisecondsTimeout)); + millisecondsTimeout), cancellationToken); } - private bool IsKeyAvailable(CancellationToken cancellationToken) + private static bool IsKeyAvailable(CancellationToken cancellationToken) { s_stdInHandle.Wait(cancellationToken); try @@ -280,7 +280,7 @@ private bool IsKeyAvailable(CancellationToken cancellationToken) } } - private async Task IsKeyAvailableAsync(CancellationToken cancellationToken) + private async static Task IsKeyAvailableAsync(CancellationToken cancellationToken) { await s_stdInHandle.WaitAsync(cancellationToken).ConfigureAwait(false); try diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetCommentHelpHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetCommentHelpHandler.cs index 934ba5138..dfab76aa0 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetCommentHelpHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetCommentHelpHandler.cs @@ -42,7 +42,7 @@ public async Task Handle(CommentHelpRequestParams requ int triggerLine = request.TriggerPosition.Line + 1; - FunctionDefinitionAst functionDefinitionAst = _symbolsService.GetFunctionDefinitionForHelpComment( + FunctionDefinitionAst functionDefinitionAst = SymbolsService.GetFunctionDefinitionForHelpComment( scriptFile, triggerLine, out string helpLocation); diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs index 8cbbd57b2..ec629b66b 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Handlers/GetVersionHandler.cs @@ -77,7 +77,7 @@ private enum PowerShellProcessArchitecture private async Task CheckPackageManagement() { PSCommand getModule = new PSCommand().AddCommand("Get-Module").AddParameter("ListAvailable").AddParameter("Name", "PackageManagement"); - foreach (PSModuleInfo module in await _powerShellContextService.ExecuteCommandAsync(getModule)) + foreach (PSModuleInfo module in await _powerShellContextService.ExecuteCommandAsync(getModule).ConfigureAwait(false)) { // The user has a good enough version of PackageManagement if (module.Version >= s_desiredPackageManagementVersion) @@ -109,7 +109,7 @@ private async Task CheckPackageManagement() Title = "Not now" } } - }); + }).ConfigureAwait(false); // If the user chose "Not now" ignore it for the rest of the session. if (messageAction?.Title == takeActionText) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index c2194a9bd..37a21a69d 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -11,6 +11,7 @@ using System.Management.Automation.Remoting; using System.Management.Automation.Runspaces; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -30,7 +31,7 @@ namespace Microsoft.PowerShell.EditorServices.Services /// Handles nested PowerShell prompts and also manages execution of /// commands whether inside or outside of the debugger. /// - internal class PowerShellContextService : IHostSupportsInteractiveSession + internal class PowerShellContextService: IHostSupportsInteractiveSession { // This is a default that can be overriden at runtime by the user or tests. private static string s_bundledModulePath = Path.GetFullPath(Path.Combine( @@ -45,6 +46,10 @@ internal class PowerShellContextService : IHostSupportsInteractiveSession "Commands", "PowerShellEditorServices.Commands.psd1")); + private static string s_psReadLineModulePath => Path.GetFullPath(Path.Combine( + s_bundledModulePath, + "PSReadLine")); + private static readonly Action s_runspaceApartmentStateSetter; private static readonly PropertyInfo s_writeStreamProperty; private static readonly object s_errorStreamValue; @@ -180,17 +185,17 @@ public RunspaceDetails CurrentRunspace public PowerShellContextService( ILogger logger, OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServerFacade languageServer, - bool isPSReadLineEnabled) + HostStartupInfo hostStartupInfo) { logger.LogTrace("Instantiating PowerShellContextService and adding event handlers"); _languageServer = languageServer; this.logger = logger; - this.isPSReadLineEnabled = isPSReadLineEnabled; + this.isPSReadLineEnabled = hostStartupInfo.ConsoleReplEnabled + && !hostStartupInfo.UsesLegacyReadLine; RunspaceChanged += PowerShellContext_RunspaceChangedAsync; ExecutionStatusChanged += PowerShellContext_ExecutionStatusChangedAsync; } - [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "Checked by Validate call")] public static PowerShellContextService Create( ILoggerFactory factory, @@ -201,24 +206,14 @@ public static PowerShellContextService Create( Validate.IsNotNull(nameof(hostStartupInfo), hostStartupInfo); - // Respect a user provided bundled module path. - if (Directory.Exists(hostStartupInfo.BundledModulePath)) - { - logger.LogTrace($"Using new bundled module path: {hostStartupInfo.BundledModulePath}"); - s_bundledModulePath = hostStartupInfo.BundledModulePath; - } - - bool shouldUsePSReadLine = hostStartupInfo.ConsoleReplEnabled - && !hostStartupInfo.UsesLegacyReadLine; - var powerShellContext = new PowerShellContextService( logger, languageServer, - shouldUsePSReadLine); + hostStartupInfo); EditorServicesPSHostUserInterface hostUserInterface = hostStartupInfo.ConsoleReplEnabled - ? (EditorServicesPSHostUserInterface) new TerminalPSHostUserInterface(powerShellContext, hostStartupInfo.PSHost, logger) + ? (EditorServicesPSHostUserInterface)new TerminalPSHostUserInterface(powerShellContext, hostStartupInfo.PSHost, logger) : new ProtocolPSHostUserInterface(languageServer, powerShellContext, logger); EditorServicesPSHost psHost = @@ -230,26 +225,7 @@ public static PowerShellContextService Create( logger.LogTrace("Creating initial PowerShell runspace"); 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) - { - 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); -#pragma warning restore CS4014 - } + powerShellContext.Initialize(hostStartupInfo, initialRunspace, true, hostUserInterface); return powerShellContext; } @@ -311,7 +287,7 @@ public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initial /// If true, the PowerShellContext owns this runspace. /// An IHostOutput implementation. Optional. public void Initialize( - ProfilePathInfo profilePaths, + HostStartupInfo hostStartupInfo, Runspace initialRunspace, bool ownsInitialRunspace, IHostOutput consoleHost) @@ -342,7 +318,12 @@ public void Initialize( RunspaceContext.Original, connectionString: null); this.CurrentRunspace = this.initialRunspace; - + // Respect a user provided bundled module path. + if (Directory.Exists(hostStartupInfo.BundledModulePath)) + { + logger.LogTrace($"Using new bundled module path: {hostStartupInfo.BundledModulePath}"); + s_bundledModulePath = hostStartupInfo.BundledModulePath; + } // Write out the PowerShell version for tracking purposes this.logger.LogInformation($"PowerShell Version: {this.LocalPowerShellVersion.Version}, Edition: {this.LocalPowerShellVersion.Edition}"); @@ -365,7 +346,7 @@ public void Initialize( this.ConfigureRunspaceCapabilities(this.CurrentRunspace); // Set the $profile variable in the runspace - this.profilePaths = profilePaths; + this.profilePaths = hostStartupInfo.ProfilePaths; if (profilePaths != null) { this.SetProfileVariableInCurrentRunspace(profilePaths); @@ -399,10 +380,47 @@ public void Initialize( this.ConsoleReader, this.versionSpecificOperations); this.InvocationEventQueue = InvocationEventQueue.Create(this, this.PromptNest); + this.ImportCommandsModuleAsync().GetAwaiter().GetResult(); + if (isPSReadLineEnabled) + { + this.ImportPSReadLine2ModuleAsync().GetAwaiter().GetResult(); + } + // 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) + { + 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 + this.ExecuteCommandAsync( + command, + sendOutputToHost: false, + sendErrorToHost: true).GetAwaiter().GetResult(); +#pragma warning restore CS4014 + } + + + // Import the PowerShellEditorServices.Commands module into the runspace. + this.ImportModuleAsync(s_commandsModulePath).GetAwaiter().GetResult(); + if (isPSReadLineEnabled) + { + // Imports the PSReadLine2 module into the runspace. + ImportModuleAsync(s_psReadLineModulePath).GetAwaiter().GetResult(); + } + // 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) + { + this.ImportModuleAsync(module).GetAwaiter().GetResult(); + } if (powerShellVersion.Major >= 5 && this.isPSReadLineEnabled && - PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, s_bundledModulePath, out PSReadLineProxy proxy)) + PSReadLinePromptContext.TryGetPSReadLineProxy(logger, out PSReadLineProxy proxy)) { this.PromptContext = new PSReadLinePromptContext( this, @@ -414,24 +432,18 @@ public void Initialize( { this.PromptContext = new LegacyReadLineContext(this); } - // Finally, restore the runspace's execution policy to the user's policy instead of // Bypass. this.RestoreExecutionPolicy(); } - /// - /// Imports the PowerShellEditorServices.Commands module into - /// the runspace. This method will be moved somewhere else soon. - /// - /// - public Task ImportCommandsModuleAsync() + public Task ImportModuleAsync(string path) { - this.logger.LogTrace($"Importing PowershellEditorServices commands from {s_commandsModulePath}"); + this.logger.LogTrace($"Importing PowershellEditorServices commands from {path}"); PSCommand importCommand = new PSCommand() .AddCommand("Import-Module") - .AddArgument(s_commandsModulePath); + .AddArgument(path); return this.ExecuteCommandAsync(importCommand, sendOutputToHost: false, sendErrorToHost: false); } @@ -485,7 +497,7 @@ private void CleanupRunspace(RunspaceDetails runspaceDetails) /// A RunspaceHandle instance that gives access to the session's runspace. public Task GetRunspaceHandleAsync() { - return this.GetRunspaceHandleImplAsync(CancellationToken.None, isReadLine: false); + return this.GetRunspaceHandleImplAsync(isReadLine: false, CancellationToken.None); } /// @@ -497,7 +509,7 @@ public Task GetRunspaceHandleAsync() /// A RunspaceHandle instance that gives access to the session's runspace. public Task GetRunspaceHandleAsync(CancellationToken cancellationToken) { - return this.GetRunspaceHandleImplAsync(cancellationToken, isReadLine: false); + return this.GetRunspaceHandleImplAsync(isReadLine: false, cancellationToken); } /// @@ -994,7 +1006,7 @@ public Task> ExecuteScriptStringAsync( Validate.IsNotNull(nameof(scriptString), scriptString); PSCommand command = null; - if(CurrentRunspace.Runspace.SessionStateProxy.LanguageMode != PSLanguageMode.FullLanguage) + if (CurrentRunspace.Runspace.SessionStateProxy.LanguageMode != PSLanguageMode.FullLanguage) { try { @@ -1009,7 +1021,7 @@ public Task> ExecuteScriptStringAsync( } // fall back to old behavior - if(command == null) + if (command == null) { command = new PSCommand().AddScript(scriptString.Trim()); } @@ -1415,12 +1427,12 @@ public void Close() private Task GetRunspaceHandleAsync(bool isReadLine) { - return this.GetRunspaceHandleImplAsync(CancellationToken.None, isReadLine); + return this.GetRunspaceHandleImplAsync(isReadLine, CancellationToken.None); } - private Task GetRunspaceHandleImplAsync(CancellationToken cancellationToken, bool isReadLine) + private Task GetRunspaceHandleImplAsync(bool isReadLine, CancellationToken cancellationToken) { - return this.PromptNest.GetRunspaceHandleAsync(cancellationToken, isReadLine); + return this.PromptNest.GetRunspaceHandleAsync(isReadLine, cancellationToken); } private ExecutionTarget GetExecutionTarget(ExecutionOptions options = null) @@ -1707,7 +1719,7 @@ internal static string QuoteEscapeString(string escapedPath) internal static string WildcardEscapePath(string path, bool escapeSpaces = false) { var sb = new StringBuilder(); - for (int i = 0; i < path.Length; i++) + for (int i = 0;i < path.Length;i++) { char curr = path[i]; switch (curr) @@ -1760,7 +1772,7 @@ internal static string UnescapeWildcardEscapedPath(string wildcardEscapedPath) } var sb = new StringBuilder(wildcardEscapedPath.Length); - for (int i = 0; i < wildcardEscapedPath.Length; i++) + for (int i = 0;i < wildcardEscapedPath.Length;i++) { // If we see a backtick perform a lookahead char curr = wildcardEscapedPath[i]; @@ -2360,7 +2372,7 @@ private static IEnumerable GetLoadableProfilePaths(ProfilePathInfo profi yield break; } - foreach (string path in new [] { profilePaths.AllUsersAllHosts, profilePaths.AllUsersCurrentHost, profilePaths.CurrentUserAllHosts, profilePaths.CurrentUserCurrentHost }) + foreach (string path in new[] { profilePaths.AllUsersAllHosts, profilePaths.AllUsersCurrentHost, profilePaths.CurrentUserAllHosts, profilePaths.CurrentUserCurrentHost }) { if (path != null && File.Exists(path)) { diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/RemoteFileManagerService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/RemoteFileManagerService.cs index 4fdc6e6bf..2685067a5 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/RemoteFileManagerService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/RemoteFileManagerService.cs @@ -319,7 +319,7 @@ public async Task FetchRemoteFileAsync( if (fileContent != null) { - this.StoreRemoteFile(localFilePath, fileContent, pathMappings); + RemoteFileManagerService.StoreRemoteFile(localFilePath, fileContent, pathMappings); } else { @@ -475,7 +475,7 @@ private string StoreRemoteFile( RemotePathMappings pathMappings = this.GetPathMappings(runspaceDetails); string localFilePath = pathMappings.GetMappedPath(remoteFilePath); - this.StoreRemoteFile( + RemoteFileManagerService.StoreRemoteFile( localFilePath, fileContent, pathMappings); @@ -483,7 +483,7 @@ private string StoreRemoteFile( return localFilePath; } - private void StoreRemoteFile( + private static void StoreRemoteFile( string localFilePath, byte[] fileContent, RemotePathMappings pathMappings) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHost.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHost.cs index 37822cb43..9cbc1fef7 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHost.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHost.cs @@ -83,7 +83,7 @@ internal class ConsoleColorProxy internal ConsoleColorProxy(EditorServicesPSHostUserInterface hostUserInterface) { - if (hostUserInterface == null) throw new ArgumentNullException("hostUserInterface"); + if (hostUserInterface == null) throw new ArgumentNullException(nameof(hostUserInterface)); _hostUserInterface = hostUserInterface; } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/InvocationEventQueue.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/InvocationEventQueue.cs index ec14ab7bb..4d7a87fd0 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/InvocationEventQueue.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/InvocationEventQueue.cs @@ -113,7 +113,7 @@ internal async Task InvokeOnPipelineThreadAsync(Action invocationAct { var request = new InvocationRequest(pwsh => { - using (_promptNest.GetRunspaceHandle(CancellationToken.None, isReadLine: false)) + using (_promptNest.GetRunspaceHandle(isReadLine: false, CancellationToken.None)) { pwsh.Runspace = _runspace; invocationAction(pwsh); @@ -223,7 +223,7 @@ private void OnInvokerUnsubscribed(object sender, PSEventUnsubscribedEventArgs e CreateInvocationSubscriber(); } - private void SetSubscriberExecutionThreadWithReflection(PSEventSubscriber subscriber) + private static void SetSubscriberExecutionThreadWithReflection(PSEventSubscriber subscriber) { // We need to create the PowerShell object in the same thread so we can get a nested // PowerShell. This is the only way to consistently take control of the pipeline. The diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs index ee4c50634..973322a6f 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs @@ -15,7 +15,7 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShellContext using System.IO; using System.Management.Automation; - internal class PSReadLinePromptContext : IPromptContext + internal class PSReadLinePromptContext: IPromptContext { private static readonly Lazy s_lazyInvokeReadLineForEditorServicesCmdletInfo = new Lazy(() => { @@ -64,59 +64,46 @@ internal PSReadLinePromptContext( internal static bool TryGetPSReadLineProxy( ILogger logger, - Runspace runspace, - string bundledModulePath, out PSReadLineProxy readLineProxy) { readLineProxy = null; logger.LogTrace("Attempting to load PSReadLine"); - using (var pwsh = PowerShell.Create()) - { - pwsh.Runspace = runspace; - pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module") - .AddParameter("Name", Path.Combine(bundledModulePath, "PSReadLine")) - .Invoke(); - - if (pwsh.HadErrors) - { - logger.LogWarning("PSConsoleReadline type not found: {Reason}", pwsh.Streams.Error[0].ToString()); - return false; - } - - var psReadLineType = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2"); + var psReadLineType = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2"); + if (psReadLineType == null) + { + // NOTE: For some reason `Type.GetType(...)` can fail to find the type, + // and in that case, this search through the `AppDomain` for some reason will succeed. + // It's slower, but only happens when needed. + logger.LogTrace("PSConsoleReadline type not found using Type.GetType(), searching all loaded assemblies..."); + psReadLineType = AppDomain.CurrentDomain + .GetAssemblies() + .FirstOrDefault(asm => asm.GetName().Name.Equals("Microsoft.PowerShell.PSReadLine2")) + ?.ExportedTypes + ?.FirstOrDefault(type => type.FullName.Equals("Microsoft.PowerShell.PSConsoleReadLine")); if (psReadLineType == null) { - // NOTE: For some reason `Type.GetType(...)` can fail to find the type, - // and in that case, this search through the `AppDomain` for some reason will succeed. - // It's slower, but only happens when needed. - logger.LogTrace("PSConsoleReadline type not found using Type.GetType(), searching all loaded assemblies..."); - psReadLineType = AppDomain.CurrentDomain - .GetAssemblies() - .FirstOrDefault(asm => asm.GetName().Name.Equals("Microsoft.PowerShell.PSReadLine2")) - ?.ExportedTypes - ?.FirstOrDefault(type => type.FullName.Equals("Microsoft.PowerShell.PSConsoleReadLine")); - if (psReadLineType == null) - { - logger.LogWarning("PSConsoleReadLine type not found anywhere!"); - return false; - } - } - - try - { - readLineProxy = new PSReadLineProxy(psReadLineType, logger); - } - catch (InvalidOperationException e) - { - // The Type we got back from PowerShell doesn't have the members we expected. - // Could be an older version, a custom build, or something a newer version with - // breaking changes. - logger.LogWarning("PSReadLineProxy unable to be initialized: {Reason}", e); + logger.LogWarning("PSConsoleReadLine type not found anywhere!"); return false; } } - + try + { + readLineProxy = new PSReadLineProxy(psReadLineType, logger); + } + catch (InvalidOperationException e) + { + // The Type we got back from PowerShell doesn't have the members we expected. + // Could be an older version, a custom build, or something a newer version with + // breaking changes. + logger.LogWarning("PSReadLineProxy unable to be initialized: {Reason}", e); + return false; + } + catch (CommandNotFoundException e) + { + logger.LogWarning("PSReadLineProxy unable to be initialized: {Reason}", e); + return false; + } return true; } @@ -164,7 +151,8 @@ public void AbortReadLine() WaitForReadLineExit(); } - public async Task AbortReadLineAsync() { + public async Task AbortReadLineAsync() + { if (_readLineCancellationSource == null) { return; @@ -177,12 +165,12 @@ public async Task AbortReadLineAsync() { public void WaitForReadLineExit() { - using (_promptNest.GetRunspaceHandle(CancellationToken.None, isReadLine: true)) + using (_promptNest.GetRunspaceHandle(isReadLine: true, CancellationToken.None)) { } } public async Task WaitForReadLineExitAsync() { - using (await _promptNest.GetRunspaceHandleAsync(CancellationToken.None, isReadLine: true).ConfigureAwait(false)) + using (await _promptNest.GetRunspaceHandleAsync(isReadLine: true, CancellationToken.None).ConfigureAwait(false)) { } } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PromptNest.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PromptNest.cs index 482ec6a31..208353632 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PromptNest.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PromptNest.cs @@ -253,7 +253,7 @@ internal PowerShell GetPowerShell(bool isReadLine = false) /// /// Indicates whether this is for a PSReadLine command. /// The for the current frame. - internal RunspaceHandle GetRunspaceHandle(CancellationToken cancellationToken, bool isReadLine) + internal RunspaceHandle GetRunspaceHandle(bool isReadLine, CancellationToken cancellationToken) { if (_isDisposed) { @@ -264,10 +264,10 @@ internal RunspaceHandle GetRunspaceHandle(CancellationToken cancellationToken, b // is in process. if (isReadLine && !_powerShellContext.IsCurrentRunspaceOutOfProcess()) { - GetRunspaceHandleImpl(cancellationToken, isReadLine: false); + GetRunspaceHandleImpl(isReadLine: false, cancellationToken); } - return GetRunspaceHandleImpl(cancellationToken, isReadLine); + return GetRunspaceHandleImpl(isReadLine, cancellationToken); } @@ -284,7 +284,7 @@ internal RunspaceHandle GetRunspaceHandle(CancellationToken cancellationToken, b /// The property will return the /// for the current frame. /// - internal async Task GetRunspaceHandleAsync(CancellationToken cancellationToken, bool isReadLine) + internal async Task GetRunspaceHandleAsync(bool isReadLine, CancellationToken cancellationToken) { if (_isDisposed) { @@ -295,10 +295,10 @@ internal async Task GetRunspaceHandleAsync(CancellationToken can // is in process. if (isReadLine && !_powerShellContext.IsCurrentRunspaceOutOfProcess()) { - await GetRunspaceHandleImplAsync(cancellationToken, isReadLine: false).ConfigureAwait(false); + await GetRunspaceHandleImplAsync(isReadLine: false, cancellationToken).ConfigureAwait(false); } - return await GetRunspaceHandleImplAsync(cancellationToken, isReadLine).ConfigureAwait(false); + return await GetRunspaceHandleImplAsync(isReadLine, cancellationToken).ConfigureAwait(false); } /// @@ -517,7 +517,7 @@ private AsyncQueue NewHandleQueue() return queue; } - private RunspaceHandle GetRunspaceHandleImpl(CancellationToken cancellationToken, bool isReadLine) + private RunspaceHandle GetRunspaceHandleImpl(bool isReadLine, CancellationToken cancellationToken) { if (isReadLine) { @@ -527,7 +527,7 @@ private RunspaceHandle GetRunspaceHandleImpl(CancellationToken cancellationToken return CurrentFrame.Queue.Dequeue(cancellationToken); } - private async Task GetRunspaceHandleImplAsync(CancellationToken cancellationToken, bool isReadLine) + private async Task GetRunspaceHandleImplAsync(bool isReadLine, CancellationToken cancellationToken) { if (isReadLine) { diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs index 63f97c83c..bbbd24484 100644 --- a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs +++ b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs @@ -144,7 +144,7 @@ public List FindSymbolsInFile(ScriptFile scriptFile) /// A SymbolReference of the symbol found at the given location /// or null if there is no symbol at that location /// - public SymbolReference FindSymbolAtLocation( + public static SymbolReference FindSymbolAtLocation( ScriptFile scriptFile, int lineNumber, int columnNumber) @@ -243,7 +243,7 @@ public List FindReferencesOfSymbol( /// The line number of the cursor for the given script /// The coulumn number of the cursor for the given script /// FindOccurrencesResult - public IReadOnlyList FindOccurrencesInFile( + public static IReadOnlyList FindOccurrencesInFile( ScriptFile file, int symbolLineNumber, int symbolColumnNumber) @@ -273,7 +273,7 @@ public IReadOnlyList FindOccurrencesInFile( /// A SymbolReference of the symbol found at the given location /// or null if there is no symbol at that location /// - public SymbolReference FindFunctionDefinitionAtLocation( + public static SymbolReference FindFunctionDefinitionAtLocation( ScriptFile scriptFile, int lineNumber, int columnNumber) @@ -573,7 +573,7 @@ private ScriptFile[] GetBuiltinCommandScriptFiles( /// The 1 based line on which to look for function definition. /// /// If found, returns the function definition, otherwise, returns null. - public FunctionDefinitionAst GetFunctionDefinitionForHelpComment( + public static FunctionDefinitionAst GetFunctionDefinitionForHelpComment( ScriptFile scriptFile, int lineNumber, out string helpLocation) @@ -647,7 +647,7 @@ public FunctionDefinitionAst GetFunctionDefinitionForHelpComment( /// Open script file. /// The 1 based line on which to look for function definition. /// If found, returns the function definition on the given line. Otherwise, returns null. - public FunctionDefinitionAst GetFunctionDefinitionAtLine( + public static FunctionDefinitionAst GetFunctionDefinitionAtLine( ScriptFile scriptFile, int lineNumber) { diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs index bb17befd8..e9972b12d 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs @@ -62,7 +62,7 @@ public static async Task GetCompletionsAsync( ILogger logger, CancellationToken cancellationToken) { - if (!s_completionHandle.Wait(0)) + if (!s_completionHandle.Wait(0, cancellationToken)) { return null; } diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs index 44f0f28f5..e0c10e5a2 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs @@ -71,7 +71,7 @@ public override AstVisitAction VisitVariableExpression(VariableExpressionAst var return AstVisitAction.Continue; } - private bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst) + private static bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst) { Ast parent = variableExpressionAst.Parent; if (!(parent is AssignmentStatementAst)) diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs index 13b351098..4c77fe934 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs @@ -103,7 +103,7 @@ await GetCompletionsInFileAsync( } } - public bool CanResolve(CompletionItem value) + public static bool CanResolve(CompletionItem value) { return value.Kind == CompletionItemKind.Function; } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs index 23a581fb1..ec47f7716 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs @@ -42,7 +42,7 @@ public override async Task Handle(DefinitionParams requ ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); SymbolReference foundSymbol = - _symbolsService.FindSymbolAtLocation( + SymbolsService.FindSymbolAtLocation( scriptFile, request.Position.Line + 1, request.Position.Character + 1); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs index 41b5669df..66b436297 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs @@ -44,7 +44,7 @@ public override Task Handle( { ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); - IReadOnlyList symbolOccurrences = _symbolsService.FindOccurrencesInFile( + IReadOnlyList symbolOccurrences = SymbolsService.FindOccurrencesInFile( scriptFile, request.Position.Line + 1, request.Position.Character + 1); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs index e1fb105d9..0b8560644 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs @@ -39,7 +39,7 @@ public override Task Handle(ReferenceParams request, Cancella ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); SymbolReference foundSymbol = - _symbolsService.FindSymbolAtLocation( + SymbolsService.FindSymbolAtLocation( scriptFile, request.Position.Line + 1, request.Position.Character + 1); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs index e8e423f07..ed69b6f09 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs @@ -26,7 +26,7 @@ class PsesTextDocumentHandler : TextDocumentSyncHandlerBase private readonly WorkspaceService _workspaceService; private readonly RemoteFileManagerService _remoteFileManagerService; - public TextDocumentSyncKind Change => TextDocumentSyncKind.Incremental; + public static TextDocumentSyncKind Change => TextDocumentSyncKind.Incremental; public PsesTextDocumentHandler( ILoggerFactory factory, diff --git a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs index b357c0410..6f6c07d88 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs @@ -14,9 +14,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.TextDocument /// internal static class TokenOperations { - // Region kinds to align with VSCode's region kinds - private const string RegionKindComment = "comment"; - private const string RegionKindRegion = "region"; private static readonly FoldingRangeKind? RegionKindNone = null; // These regular expressions are used to match lines which mark the start and end of region comment in a PowerShell diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs index a17b11380..fa31308d0 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs @@ -73,7 +73,7 @@ public override Task> Handle(WorkspaceSymbolParams #region private Methods - private bool IsQueryMatch(string query, string symbolName) + private static bool IsQueryMatch(string query, string symbolName) { return symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; } diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs index 8ae11da0d..5c922e886 100644 --- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs @@ -41,7 +41,7 @@ public async Task InitializeAsync() { var factory = new LoggerFactory(); _psesProcess = new PsesStdioProcess(factory, true); - await _psesProcess.Start(); + await _psesProcess.Start().ConfigureAwait(false); var initialized = new TaskCompletionSource(); PsesDebugAdapterClient = DebugAdapterClient.Create(options => @@ -99,7 +99,7 @@ await PsesDebugAdapterClient.RequestDisconnect(new DisconnectArguments } } - private string NewTestFile(string script, bool isPester = false) + private static string NewTestFile(string script, bool isPester = false) { string fileExt = isPester ? ".Tests.ps1" : ".ps1"; string filePath = Path.Combine(s_binDir, Path.GetRandomFileName() + fileExt); @@ -128,7 +128,7 @@ private string GenerateScriptFromLoggingStatements(params string[] logStatements return builder.ToString(); } - private string[] GetLog() + private static string[] GetLog() { return File.ReadLines(s_testOutputPath).ToArray(); } diff --git a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs index 22c1074c9..3bdd47096 100644 --- a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs +++ b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs @@ -43,7 +43,7 @@ public async Task InitializeAsync() { var factory = new LoggerFactory(); _psesProcess = new PsesStdioProcess(factory, IsDebugAdapterTests); - await _psesProcess.Start(); + await _psesProcess.Start().ConfigureAwait(false); Diagnostics = new List(); TelemetryEvents = new List(); diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index 4db662493..276df5666 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -35,8 +35,6 @@ public class LanguageServerProtocolMessageTests : IClassFixture private readonly static string s_binDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - private static bool s_registeredOnLogMessage; - private readonly ILanguageClient PsesLanguageClient; private readonly List Diagnostics; private readonly List TelemetryEvents; @@ -94,7 +92,7 @@ private async Task WaitForDiagnosticsAsync() throw new InvalidDataException("No diagnostics showed up after 20s."); } - await Task.Delay(2000); + await Task.Delay(2000).ConfigureAwait(false); i++; } } @@ -110,7 +108,7 @@ private async Task WaitForTelemetryEventsAsync() throw new InvalidDataException("No telemetry events showed up after 20s."); } - await Task.Delay(2000); + await Task.Delay(2000).ConfigureAwait(false); i++; } } @@ -122,7 +120,7 @@ public async Task CanSendPowerShellGetVersionRequestAsync() PowerShellVersion details = await PsesLanguageClient .SendRequest("powerShell/getVersion", new GetVersionParams()) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); if(PwshExe == "powershell") { @@ -152,7 +150,7 @@ function CanSendWorkspaceSymbolRequest { { Query = "CanSendWorkspaceSymbolRequest" }) - .Returning>(CancellationToken.None); + .Returning>(CancellationToken.None).ConfigureAwait(false); SymbolInformation symbol = Assert.Single(symbols); Assert.Equal("CanSendWorkspaceSymbolRequest { }", symbol.Name); @@ -167,7 +165,7 @@ public async Task CanReceiveDiagnosticsFromFileOpenAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); NewTestFile("$a = 4"); - await WaitForDiagnosticsAsync(); + await WaitForDiagnosticsAsync().ConfigureAwait(false); Diagnostic diagnostic = Assert.Single(Diagnostics); Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); @@ -178,7 +176,7 @@ public async Task CanReceiveDiagnosticsFromFileOpenAsync() public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShellAsync() { NewTestFile("$a = 4", languageId: "plaintext"); - await Task.Delay(2000); + await Task.Delay(2000).ConfigureAwait(false); Assert.Empty(Diagnostics); } @@ -192,7 +190,7 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); string filePath = NewTestFile("$a = 4"); - await WaitForDiagnosticsAsync(); + await WaitForDiagnosticsAsync().ConfigureAwait(false); Diagnostics.Clear(); PsesLanguageClient.SendNotification("textDocument/didChange", new DidChangeTextDocumentParams @@ -220,7 +218,7 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() } }); - await WaitForDiagnosticsAsync(); + await WaitForDiagnosticsAsync().ConfigureAwait(false); if (Diagnostics.Count > 1) { StringBuilder errorBuilder = new StringBuilder().AppendLine("Multiple diagnostics found when there should be only 1:"); @@ -245,7 +243,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); NewTestFile("gci | % { $_ }"); - await WaitForDiagnosticsAsync(); + await WaitForDiagnosticsAsync().ConfigureAwait(false); // NewTestFile doesn't clear diagnostic notifications so we need to do that for this test. Diagnostics.Clear(); @@ -292,7 +290,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() }); // Wait a bit to make sure no telemetry events came through - await Task.Delay(2000); + await Task.Delay(2000).ConfigureAwait(false); // Since we have default settings we should not get any telemetry events about Assert.Empty(TelemetryEvents.Where(e => e.EventName == "NonDefaultPsesFeatureConfiguration")); } @@ -320,7 +318,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning>(CancellationToken.None); + .Returning>(CancellationToken.None).ConfigureAwait(false); Assert.Collection(foldingRanges.OrderBy(f => f.StartLine), range1 => @@ -369,7 +367,7 @@ public async Task CanSendFormattingRequestAsync() InsertSpaces = false } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); TextEdit textEdit = Assert.Single(textEdits); @@ -420,7 +418,7 @@ public async Task CanSendRangeFormattingRequestAsync() InsertSpaces = false } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); TextEdit textEdit = Assert.Single(textEdits); @@ -451,7 +449,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(symbolInformationOrDocumentSymbols, symInfoOrDocSym => { @@ -495,7 +493,7 @@ function CanSendReferencesRequest { IncludeDeclaration = false } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(locations, location1 => @@ -543,7 +541,7 @@ await PsesLanguageClient Character = 1 } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(documentHighlights, documentHighlight1 => @@ -596,7 +594,7 @@ await PsesLanguageClient .SendRequest( "powerShell/getPSHostProcesses", new GetPSHostProcesssesParams { }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); } finally { @@ -640,7 +638,7 @@ await PsesLanguageClient { ProcessId = $"{process.Id}" }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); } finally { @@ -690,7 +688,7 @@ public async Task CanSendPesterLegacyCodeLensRequestAsync() Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(codeLenses, codeLens1 => @@ -756,7 +754,7 @@ public async Task CanSendPesterCodeLensRequestAsync() Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(codeLenses, codeLens => @@ -849,7 +847,7 @@ function CanSendReferencesCodeLensRequest { Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); CodeLens codeLens = Assert.Single(codeLenses); @@ -861,7 +859,7 @@ function CanSendReferencesCodeLensRequest { CodeLens codeLensResolveResult = await PsesLanguageClient .SendRequest("codeLens/resolve", codeLens) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } @@ -875,7 +873,7 @@ public async Task CanSendCodeActionRequestAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); string filePath = NewTestFile("gci"); - await WaitForDiagnosticsAsync(); + await WaitForDiagnosticsAsync().ConfigureAwait(false); CommandOrCodeActionContainer commandOrCodeActions = await PsesLanguageClient @@ -903,7 +901,7 @@ await PsesLanguageClient Diagnostics = new Container(Diagnostics) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(commandOrCodeActions, command => @@ -946,7 +944,7 @@ public async Task CanSendCompletionAndCompletionResolveRequestAsync() CompletionItem updatedCompletionItem = await PsesLanguageClient .SendRequest("completionItem/resolve", completionItem) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Contains("Writes customized output to a host", updatedCompletionItem.Documentation.String); } @@ -962,7 +960,7 @@ await PsesLanguageClient { Expression = "Import-Module Microsoft.PowerShell.Archive -Prefix Slow" }) - .ReturningVoid(CancellationToken.None); + .ReturningVoid(CancellationToken.None).ConfigureAwait(false); string filePath = NewTestFile("Expand-SlowArch"); @@ -981,7 +979,7 @@ await PsesLanguageClient CompletionItem updatedCompletionItem = await PsesLanguageClient .SendRequest("completionItem/resolve", completionItem) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Contains("Extracts files from a specified archive", updatedCompletionItem.Documentation.String); } @@ -1001,7 +999,7 @@ public async Task CanSendHoverRequestAsync() Uri = DocumentUri.FromFileSystemPath(filePath) }, Position = new Position(line: 0, character: 1) - }); + }).ConfigureAwait(false); Assert.True(hover.Contents.HasMarkedStrings); Assert.Collection(hover.Contents.MarkedStrings, @@ -1037,7 +1035,7 @@ public async Task CanSendSignatureHelpRequestAsync() Character = 9 } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Contains("Get-Date", signatureHelp.Signatures.First().Label); } @@ -1070,7 +1068,7 @@ await PsesLanguageClient Character = 2 } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); LocationOrLocationLink locationOrLocationLink = Assert.Single(locationOrLocationLinks); @@ -1095,7 +1093,7 @@ await PsesLanguageClient { IncludeInstalledModules = true }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Collection(getProjectTemplatesResponse.Templates.OrderBy(t => t.Title), template1 => @@ -1143,7 +1141,7 @@ await PsesLanguageClient Character = 0 } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.NotEmpty(commentHelpRequestResult.Content); Assert.Contains("myParam", commentHelpRequestResult.Content[7]); @@ -1161,7 +1159,7 @@ await PsesLanguageClient { Expression = "Get-ChildItem" }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); // These always gets returned so this test really just makes sure we get _any_ response. Assert.Equal("", evaluateResponseBody.Result); @@ -1175,7 +1173,7 @@ public async Task CanSendGetCommandRequestAsync() List pSCommandMessages = await PsesLanguageClient .SendRequest("powerShell/getCommand", new GetCommandParams()) - .Returning>(CancellationToken.None); + .Returning>(CancellationToken.None).ConfigureAwait(false); Assert.NotEmpty(pSCommandMessages); // There should be at least 20 commands or so. @@ -1198,7 +1196,7 @@ await PsesLanguageClient { Text = "gci" }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); Assert.Equal("Get-ChildItem", expandAliasResult.Text); } @@ -1221,7 +1219,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning(CancellationToken.None); + .Returning(CancellationToken.None).ConfigureAwait(false); // More information about how this data is generated can be found at // https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index c50895f2e..883836b9f 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs b/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs index a7048f7d2..585e1bf03 100644 --- a/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs +++ b/test/PowerShellEditorServices.Test.E2E/Processes/StdioServerProcess.cs @@ -123,7 +123,7 @@ public override async Task Stop() serverProcess.Kill(); } - await ServerExitCompletion.Task; + await ServerExitCompletion.Task.ConfigureAwait(false); } /// diff --git a/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs b/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs index 87649c6b9..f29c625be 100644 --- a/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs +++ b/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs @@ -14,8 +14,6 @@ namespace Microsoft.PowerShell.EditorServices.Test.Shared /// public static class TestUtilities { - private static readonly char[] s_unixPathSeparators = new [] { '/' }; - private static readonly char[] s_unixNewlines = new [] { '\n' }; /// diff --git a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs index 5b352f55d..c7b5ac37c 100644 --- a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs @@ -62,7 +62,7 @@ public async Task LanguageServiceCompletesCommandInFile() { CompletionResults completionResults = await this.GetCompletionResults( - CompleteCommandInFile.SourceDetails); + CompleteCommandInFile.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); Assert.Equal( @@ -76,7 +76,7 @@ public async Task LanguageServiceCompletesCommandFromModule() { CompletionResults completionResults = await this.GetCompletionResults( - CompleteCommandFromModule.SourceDetails); + CompleteCommandFromModule.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); @@ -103,7 +103,7 @@ public async Task LanguageServiceCompletesTypeName() CompletionResults completionResults = await this.GetCompletionResults( - CompleteTypeName.SourceDetails); + CompleteTypeName.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); @@ -130,7 +130,7 @@ public async Task LanguageServiceCompletesNamespace() CompletionResults completionResults = await this.GetCompletionResults( - CompleteNamespace.SourceDetails); + CompleteNamespace.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); @@ -153,7 +153,7 @@ public async Task LanguageServiceCompletesVariableInFile() { CompletionResults completionResults = await this.GetCompletionResults( - CompleteVariableInFile.SourceDetails); + CompleteVariableInFile.SourceDetails).ConfigureAwait(false); Assert.Single(completionResults.Completions); Assert.Equal( @@ -167,7 +167,7 @@ public async Task LanguageServiceCompletesAttributeValue() { CompletionResults completionResults = await this.GetCompletionResults( - CompleteAttributeValue.SourceDetails); + CompleteAttributeValue.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); Assert.Equal( @@ -181,7 +181,7 @@ public async Task LanguageServiceCompletesFilePath() { CompletionResults completionResults = await this.GetCompletionResults( - CompleteFilePath.SourceDetails); + CompleteFilePath.SourceDetails).ConfigureAwait(false); Assert.NotEmpty(completionResults.Completions); // TODO: Since this is a path completion, this test will need to be @@ -200,7 +200,7 @@ public async Task LanguageServiceFindsParameterHintsOnCommand() { ParameterSetSignatures paramSignatures = await this.GetParamSetSignatures( - FindsParameterSetsOnCommand.SourceDetails); + FindsParameterSetsOnCommand.SourceDetails).ConfigureAwait(false); Assert.NotNull(paramSignatures); Assert.Equal("Get-Process", paramSignatures.CommandName); @@ -213,7 +213,7 @@ public async Task LanguageServiceFindsCommandForParamHintsWithSpaces() { ParameterSetSignatures paramSignatures = await this.GetParamSetSignatures( - FindsParameterSetsOnCommandWithSpaces.SourceDetails); + FindsParameterSetsOnCommandWithSpaces.SourceDetails).ConfigureAwait(false); Assert.NotNull(paramSignatures); Assert.Equal("Write-Host", paramSignatures.CommandName); @@ -226,7 +226,7 @@ public async Task LanguageServiceFindsFunctionDefinition() { SymbolReference definitionResult = await this.GetDefinition( - FindsFunctionDefinition.SourceDetails); + FindsFunctionDefinition.SourceDetails).ConfigureAwait(false); Assert.Equal(1, definitionResult.ScriptRegion.StartLineNumber); Assert.Equal(10, definitionResult.ScriptRegion.StartColumnNumber); @@ -239,7 +239,7 @@ public async Task LanguageServiceFindsFunctionDefinitionInDotSourceReference() { SymbolReference definitionResult = await this.GetDefinition( - FindsFunctionDefinitionInDotSourceReference.SourceDetails); + FindsFunctionDefinitionInDotSourceReference.SourceDetails).ConfigureAwait(false); Assert.True( definitionResult.FilePath.EndsWith( @@ -256,7 +256,7 @@ public async Task LanguageServiceFindsDotSourcedFile() { SymbolReference definitionResult = await this.GetDefinition( - FindsDotSourcedFile.SourceDetails); + FindsDotSourcedFile.SourceDetails).ConfigureAwait(false); Assert.True( definitionResult.FilePath.EndsWith( @@ -273,7 +273,7 @@ public async Task LanguageServiceFindsFunctionDefinitionInWorkspace() { SymbolReference definitionResult = await this.GetDefinition( - FindsFunctionDefinitionInWorkspace.SourceDetails); + FindsFunctionDefinitionInWorkspace.SourceDetails).ConfigureAwait(false); Assert.EndsWith("ReferenceFileE.ps1", definitionResult.FilePath); Assert.Equal("My-FunctionInFileE", definitionResult.SymbolName); } @@ -284,7 +284,7 @@ public async Task LanguageServiceFindsVariableDefinition() { SymbolReference definitionResult = await this.GetDefinition( - FindsVariableDefinition.SourceDetails); + FindsVariableDefinition.SourceDetails).ConfigureAwait(false); Assert.Equal(6, definitionResult.ScriptRegion.StartLineNumber); Assert.Equal(1, definitionResult.ScriptRegion.StartColumnNumber); @@ -373,7 +373,7 @@ public async Task LanguageServiceFindsDetailsForBuiltInCommand() await this.symbolsService.FindSymbolDetailsAtLocationAsync( this.GetScriptFile(FindsDetailsForBuiltInCommand.SourceDetails), FindsDetailsForBuiltInCommand.SourceDetails.StartLineNumber, - FindsDetailsForBuiltInCommand.SourceDetails.StartColumnNumber); + FindsDetailsForBuiltInCommand.SourceDetails.StartColumnNumber).ConfigureAwait(false); Assert.NotNull(symbolDetails.Documentation); Assert.NotEqual("", symbolDetails.Documentation); @@ -460,7 +460,7 @@ private async Task GetCompletionResults(ScriptRegion scriptRe await this.completionHandler.GetCompletionsInFileAsync( GetScriptFile(scriptRegion), scriptRegion.StartLineNumber, - scriptRegion.StartColumnNumber); + scriptRegion.StartColumnNumber).ConfigureAwait(false); } private async Task GetParamSetSignatures(ScriptRegion scriptRegion) @@ -470,7 +470,7 @@ await this.symbolsService.FindParameterSetsInFileAsync( GetScriptFile(scriptRegion), scriptRegion.StartLineNumber, scriptRegion.StartColumnNumber, - powerShellContext); + powerShellContext).ConfigureAwait(false); } private async Task GetDefinition(ScriptRegion scriptRegion) @@ -478,7 +478,7 @@ private async Task GetDefinition(ScriptRegion scriptRegion) ScriptFile scriptFile = GetScriptFile(scriptRegion); SymbolReference symbolReference = - this.symbolsService.FindSymbolAtLocation( + SymbolsService.FindSymbolAtLocation( scriptFile, scriptRegion.StartLineNumber, scriptRegion.StartColumnNumber); @@ -488,7 +488,7 @@ private async Task GetDefinition(ScriptRegion scriptRegion) return await this.symbolsService.GetDefinitionOfSymbolAsync( scriptFile, - symbolReference); + symbolReference).ConfigureAwait(false); } private List GetReferences(ScriptRegion scriptRegion) @@ -496,7 +496,7 @@ private List GetReferences(ScriptRegion scriptRegion) ScriptFile scriptFile = GetScriptFile(scriptRegion); SymbolReference symbolReference = - this.symbolsService.FindSymbolAtLocation( + SymbolsService.FindSymbolAtLocation( scriptFile, scriptRegion.StartLineNumber, scriptRegion.StartColumnNumber); @@ -513,7 +513,7 @@ private List GetReferences(ScriptRegion scriptRegion) private IReadOnlyList GetOccurrences(ScriptRegion scriptRegion) { return - this.symbolsService.FindOccurrencesInFile( + SymbolsService.FindOccurrencesInFile( GetScriptFile(scriptRegion), scriptRegion.StartLineNumber, scriptRegion.StartColumnNumber); diff --git a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs index d88b7d557..53b4be337 100644 --- a/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs +++ b/test/PowerShellEditorServices.Test/Language/TokenOperationsTests.cs @@ -15,7 +15,7 @@ public class TokenOperationsTests /// /// Helper method to create a stub script file and then call FoldableRegions /// - private FoldingReference[] GetRegions(string text) { + private static FoldingReference[] GetRegions(string text) { ScriptFile scriptFile = new ScriptFile( // Use any absolute path. Even if it doesn't exist. DocumentUri.FromFileSystemPath(Path.Combine(Path.GetTempPath(), "TestFile.ps1")), @@ -153,7 +153,7 @@ double quoted herestrings should also fold /// /// Assertion helper to compare two FoldingReference arrays. /// - private void AssertFoldingReferenceArrays( + private static void AssertFoldingReferenceArrays( FoldingReference[] expected, FoldingReference[] actual) { diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 422cc58a0..92467f4c6 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Management.Automation; +using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Threading; using System.Threading.Tasks; @@ -13,7 +15,6 @@ using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; using Microsoft.PowerShell.EditorServices.Test.Shared; -using Microsoft.PowerShell.EditorServices.Utility; namespace Microsoft.PowerShell.EditorServices.Test { @@ -35,12 +36,11 @@ internal static class PowerShellContextFactory public static readonly string BundledModulePath = Path.GetFullPath( TestUtilities.NormalizePath("../../../../../module")); - public static System.Management.Automation.Runspaces.Runspace InitialRunspace; + public static PowerShellContextService Create(ILogger logger, bool isPSReadLineEnabled = false) - public static PowerShellContextService Create(ILogger logger) + public static PowerShellContextService Create(ILogger logger, bool isPSReadLineEnabled = false) { - PowerShellContextService powerShellContext = new PowerShellContextService(logger, null, isPSReadLineEnabled: false); var initialSessionState = InitialSessionState.CreateDefault(); // We set the process scope's execution policy (which is really the runspace's scope) to // `Bypass` so we can import our bundled modules. This is equivalent in scope to the CLI @@ -51,7 +51,6 @@ public static PowerShellContextService Create(ILogger logger) { initialSessionState.ExecutionPolicy = ExecutionPolicy.Bypass; } - HostStartupInfo testHostDetails = new HostStartupInfo( "PowerShell Editor Services Test Host", "Test.PowerShellEditorServices", @@ -60,13 +59,17 @@ public static PowerShellContextService Create(ILogger logger) TestProfilePaths, new List(), new List(), - initialSessionState, + // TODO: We want to replace this property with an entire initial session state, + // which would then also control the process-scoped execution policy. + PSLanguageMode.FullLanguage, null, 0, - consoleReplEnabled: false, + consoleReplEnabled: isPSReadLineEnabled, usesLegacyReadLine: false, bundledModulePath: BundledModulePath); + PowerShellContextService powerShellContext = new PowerShellContextService(logger, null, testHostDetails); + InitialRunspace = PowerShellContextService.CreateTestRunspace( testHostDetails, powerShellContext, @@ -74,7 +77,7 @@ public static PowerShellContextService Create(ILogger logger) logger); powerShellContext.Initialize( - TestProfilePaths, + testHostDetails, InitialRunspace, ownsInitialRunspace: true, consoleHost: null); diff --git a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs index ba1e07611..b25ff13b6 100644 --- a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs +++ b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.PowerShell.EditorServices.Hosting; using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.PowerShellContext; using Microsoft.PowerShell.EditorServices.Test.Shared; @@ -16,7 +17,7 @@ namespace Microsoft.PowerShell.EditorServices.Test.Console { - public class PowerShellContextTests : IDisposable + public class PowerShellContextTests: IDisposable { // Borrowed from `VersionUtils` which can't be used here due to an initialization problem. private static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); @@ -50,10 +51,10 @@ public async Task CanExecutePSCommand() var executeTask = this.powerShellContext.ExecuteCommandAsync(psCommand); - await this.AssertStateChange(PowerShellContextState.Running); - await this.AssertStateChange(PowerShellContextState.Ready); + await this.AssertStateChange(PowerShellContextState.Running).ConfigureAwait(false); + await this.AssertStateChange(PowerShellContextState.Ready).ConfigureAwait(false); - var result = await executeTask; + var result = await executeTask.ConfigureAwait(false); Assert.Equal("foo", result.First()); } @@ -72,11 +73,11 @@ public async Task CanQueueParallelRunspaceRequests() Task> resultTask = this.powerShellContext.ExecuteCommandAsync(psCommand); // Wait for the requested runspace handle and then dispose it - RunspaceHandle handle = await handleTask; + RunspaceHandle handle = await handleTask.ConfigureAwait(false); handle.Dispose(); // Wait for all of the executes to complete - await Task.WhenAll(taskOne, taskTwo, taskThree, resultTask); + await Task.WhenAll(taskOne, taskTwo, taskThree, resultTask).ConfigureAwait(false); // At this point, the remaining command executions should execute and complete int result = resultTask.Result.FirstOrDefault(); @@ -95,23 +96,23 @@ public async Task CanAbortExecution() async () => { var unusedTask = this.powerShellContext.ExecuteScriptWithArgsAsync(s_debugTestFilePath); - await Task.Delay(50); + await Task.Delay(50).ConfigureAwait(false); this.powerShellContext.AbortExecution(); }); - await this.AssertStateChange(PowerShellContextState.Running); - await this.AssertStateChange(PowerShellContextState.Aborting); - await this.AssertStateChange(PowerShellContextState.Ready); + await this.AssertStateChange(PowerShellContextState.Running).ConfigureAwait(false); + await this.AssertStateChange(PowerShellContextState.Aborting).ConfigureAwait(false); + await this.AssertStateChange(PowerShellContextState.Ready).ConfigureAwait(false); - await executeTask; + await executeTask.ConfigureAwait(false); } [Trait("Category", "PowerShellContext")] [Fact] public async Task CanResolveAndLoadProfilesForHostId() { - string[] expectedProfilePaths = - new string[] + string [] expectedProfilePaths = + new string [] { PowerShellContextFactory.TestProfilePaths.AllUsersAllHosts, PowerShellContextFactory.TestProfilePaths.AllUsersCurrentHost, @@ -120,7 +121,7 @@ public async Task CanResolveAndLoadProfilesForHostId() }; // Load the profiles for the test host name - await this.powerShellContext.LoadHostProfilesAsync(); + await this.powerShellContext.LoadHostProfilesAsync().ConfigureAwait(false); // Ensure that all the paths are set in the correct variables // and that the current user's host profile got loaded @@ -134,7 +135,7 @@ public async Task CanResolveAndLoadProfilesForHostId() var result = await this.powerShellContext.ExecuteCommandAsync( - psCommand); + psCommand).ConfigureAwait(false); string expectedString = string.Format( @@ -150,10 +151,10 @@ await this.powerShellContext.ExecuteCommandAsync( [Fact] public void CanGetPSReadLineProxy() { + // This will force the loading of the PSReadLine assembly + var psContext = PowerShellContextFactory.Create(NullLogger.Instance, isPSReadLineEnabled: true); Assert.True(PSReadLinePromptContext.TryGetPSReadLineProxy( NullLogger.Instance, - PowerShellContextFactory.InitialRunspace, - PowerShellContextFactory.BundledModulePath, out PSReadLineProxy proxy)); } @@ -162,7 +163,7 @@ public void CanGetPSReadLineProxy() private async Task AssertStateChange(PowerShellContextState expectedState) { SessionStateChangedEventArgs newState = - await this.stateChangeQueue.DequeueAsync(); + await this.stateChangeQueue.DequeueAsync().ConfigureAwait(false); Assert.Equal(expectedState, newState.NewSessionState); } @@ -175,4 +176,3 @@ private void OnSessionStateChanged(object sender, SessionStateChangedEventArgs e #endregion } } - diff --git a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs index 1663732be..4e716a1d2 100644 --- a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs +++ b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs @@ -25,7 +25,7 @@ public class ScriptFileChangeTests [Fact] public void CanApplySingleLineInsert() { - this.AssertFileChange( + AssertFileChange( "This is a test.", "This is a working test.", new FileChange @@ -42,7 +42,7 @@ public void CanApplySingleLineInsert() [Fact] public void CanApplySingleLineReplace() { - this.AssertFileChange( + AssertFileChange( "This is a potentially broken test.", "This is a working test.", new FileChange @@ -59,7 +59,7 @@ public void CanApplySingleLineReplace() [Fact] public void CanApplySingleLineDelete() { - this.AssertFileChange( + AssertFileChange( "This is a test of the emergency broadcasting system.", "This is a test.", new FileChange @@ -76,7 +76,7 @@ public void CanApplySingleLineDelete() [Fact] public void CanApplyMultiLineInsert() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("first\nsecond\nfifth"), TestUtilities.NormalizeNewlines("first\nsecond\nthird\nfourth\nfifth"), new FileChange @@ -93,7 +93,7 @@ public void CanApplyMultiLineInsert() [Fact] public void CanApplyMultiLineReplace() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("first\nsecoXX\nXXfth"), TestUtilities.NormalizeNewlines("first\nsecond\nthird\nfourth\nfifth"), new FileChange @@ -110,7 +110,7 @@ public void CanApplyMultiLineReplace() [Fact] public void CanApplyMultiLineReplaceWithRemovedLines() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("first\nsecoXX\nREMOVE\nTHESE\nLINES\nXXfth"), TestUtilities.NormalizeNewlines("first\nsecond\nthird\nfourth\nfifth"), new FileChange @@ -127,7 +127,7 @@ public void CanApplyMultiLineReplaceWithRemovedLines() [Fact] public void CanApplyMultiLineDelete() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("first\nsecond\nREMOVE\nTHESE\nLINES\nthird"), TestUtilities.NormalizeNewlines("first\nsecond\nthird"), new FileChange @@ -144,7 +144,7 @@ public void CanApplyMultiLineDelete() [Fact] public void CanApplyEditsToEndOfFile() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("line1\nline2\nline3\n\n"), TestUtilities.NormalizeNewlines("line1\nline2\nline3\n\n\n\n"), new FileChange @@ -161,7 +161,7 @@ public void CanApplyEditsToEndOfFile() [Fact] public void CanAppendToEndOfFile() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("line1\nline2\nline3"), TestUtilities.NormalizeNewlines("line1\nline2\nline3\nline4\nline5"), new FileChange @@ -208,7 +208,7 @@ public void ThrowsExceptionWithEditOutsideOfRange() Assert.Throws( () => { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("first\nsecond\nREMOVE\nTHESE\nLINES\nthird"), TestUtilities.NormalizeNewlines("first\nsecond\nthird"), new FileChange @@ -226,7 +226,7 @@ public void ThrowsExceptionWithEditOutsideOfRange() [Fact] public void CanDeleteFromEndOfFile() { - this.AssertFileChange( + AssertFileChange( TestUtilities.NormalizeNewlines("line1\nline2\nline3\nline4"), TestUtilities.NormalizeNewlines("line1\nline2"), new FileChange @@ -256,7 +256,7 @@ internal static ScriptFile CreateScriptFile(string initialString) } } - private void AssertFileChange( + private static void AssertFileChange( string initialString, string expectedString, FileChange fileChange) diff --git a/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs index 0dc8e411d..816489420 100644 --- a/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs +++ b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs @@ -14,8 +14,6 @@ namespace Microsoft.PowerShell.EditorServices.Test.Session { public class WorkspaceTests { - private static readonly Version PowerShellVersion = new Version("5.0"); - private static readonly Lazy s_lazyDriveLetter = new Lazy(() => Path.GetFullPath("\\").Substring(0, 1)); public static string CurrentDriveLetter => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) diff --git a/test/PowerShellEditorServices.Test/Utility/AsyncLockTests.cs b/test/PowerShellEditorServices.Test/Utility/AsyncLockTests.cs index 9cc9b810b..99b8bb05c 100644 --- a/test/PowerShellEditorServices.Test/Utility/AsyncLockTests.cs +++ b/test/PowerShellEditorServices.Test/Utility/AsyncLockTests.cs @@ -23,7 +23,7 @@ public async Task AsyncLockSynchronizesAccess() Assert.Equal(TaskStatus.WaitingForActivation, lockTwo.Status); lockOne.Result.Dispose(); - await lockTwo; + await lockTwo.ConfigureAwait(false); Assert.Equal(TaskStatus.RanToCompletion, lockTwo.Status); } @@ -45,4 +45,3 @@ public void AsyncLockCancelsWhenRequested() } } } - diff --git a/test/PowerShellEditorServices.Test/Utility/AsyncQueueTests.cs b/test/PowerShellEditorServices.Test/Utility/AsyncQueueTests.cs index 9e1845fa1..70c31f444 100644 --- a/test/PowerShellEditorServices.Test/Utility/AsyncQueueTests.cs +++ b/test/PowerShellEditorServices.Test/Utility/AsyncQueueTests.cs @@ -33,16 +33,16 @@ await Task.WhenAll( async () => { // Wait for a bit and then add more items to the queue - await Task.Delay(250); + await Task.Delay(250).ConfigureAwait(false); foreach (var i in Enumerable.Range(100, 200)) { - await inputQueue.EnqueueAsync(i); + await inputQueue.EnqueueAsync(i).ConfigureAwait(false); } // Cancel the waiters cancellationTokenSource.Cancel(); - })); + })).ConfigureAwait(false); } catch (TaskCanceledException) { @@ -66,7 +66,7 @@ public async Task AsyncQueueSkipsCancelledTasks() // Cancel the first task and then enqueue a number cancellationSource.Cancel(); - await inputQueue.EnqueueAsync(1); + await inputQueue.EnqueueAsync(1).ConfigureAwait(false); // Wait for things to propegate. await Task.Delay(1000).ConfigureAwait(false); @@ -77,17 +77,16 @@ public async Task AsyncQueueSkipsCancelledTasks() Assert.Equal(1, taskTwo.Result); } - private async Task ConsumeItemsAsync( + private static async Task ConsumeItemsAsync( AsyncQueue inputQueue, ConcurrentBag outputItems, CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { - int consumedItem = await inputQueue.DequeueAsync(cancellationToken); + int consumedItem = await inputQueue.DequeueAsync(cancellationToken).ConfigureAwait(false); outputItems.Add(consumedItem); } } } } - diff --git a/scripts/azurePipelinesBuild.ps1 b/tools/azurePipelinesBuild.ps1 similarity index 76% rename from scripts/azurePipelinesBuild.ps1 rename to tools/azurePipelinesBuild.ps1 index ef25e0595..3bdb78af2 100644 --- a/scripts/azurePipelinesBuild.ps1 +++ b/tools/azurePipelinesBuild.ps1 @@ -6,9 +6,9 @@ $ErrorActionPreference = 'Stop' Set-PSRepository -Name PSGallery -InstallationPolicy Trusted | Out-Null if ($IsWindows -or $PSVersionTable.PSVersion.Major -lt 6) { # We rely on PowerShellGet's -AllowPrerelease which is in PowerShellGet 1.6 so we need to update PowerShellGet. - Get-Module PowerShellGet,PackageManagement | Remove-Module -Force -Verbose - powershell -Command { Install-Module -Name PowerShellGet -MinimumVersion 1.6 -Force -Confirm:$false -Verbose } - powershell -Command { Install-Module -Name PackageManagement -MinimumVersion 1.1.7.0 -Force -Confirm:$false -Verbose } + Get-Module PowerShellGet,PackageManagement | Remove-Module -Force + powershell -Command { Install-Module -Name PowerShellGet -MinimumVersion 1.6 -Force } + powershell -Command { Install-Module -Name PackageManagement -MinimumVersion 1.1.7.0 -Force } Import-Module -Name PowerShellGet -MinimumVersion 1.6 -Force Import-Module -Name PackageManagement -MinimumVersion 1.1.7.0 -Force } @@ -17,7 +17,7 @@ if ($IsWindows -or $PSVersionTable.PSVersion.Major -lt 6) { Update-Help -Force -ErrorAction SilentlyContinue # Needed for build and docs gen. -Install-Module InvokeBuild -MaximumVersion 5.1.0 -Scope CurrentUser -Install-Module PlatyPS -RequiredVersion 0.9.0 -Scope CurrentUser +Install-Module -Name InvokeBuild -MaximumVersion 5.1.0 -Scope CurrentUser -Force +Install-Module -Name PlatyPS -RequiredVersion 0.9.0 -Scope CurrentUser -Force Invoke-Build -Configuration Release