Skip to content

Latest commit

 

History

History
176 lines (136 loc) · 8.8 KB

File metadata and controls

176 lines (136 loc) · 8.8 KB

Copilot Instructions for PowerShell Editor Services

Build & Test

Requires .NET SDK 8.0+. Use dotnet directly for building and testing — it's faster and requires no extra tooling. The Invoke-Build script requires the InvokeBuild and platyPS PowerShell modules (platyPS is #Requires'd at the top, so the whole script fails without it), and is mainly needed to assemble the full PowerShell module for release.

# Build (run both; Hosting depends on the core library)
dotnet publish src/PowerShellEditorServices/PowerShellEditorServices.csproj -f netstandard2.0
dotnet publish src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj -f net8.0

# Run all unit tests
dotnet test test/PowerShellEditorServices.Test/ --framework net8.0

# Run a single test by name
dotnet test test/PowerShellEditorServices.Test/ --framework net8.0 --filter "FullyQualifiedName~CompletesCommandInFile"

# Run tests by trait category
dotnet test test/PowerShellEditorServices.Test/ --framework net8.0 --filter "Category=Completions"

# Run E2E tests
dotnet test test/PowerShellEditorServices.Test.E2E/ --framework net8.0

For assembling the full module or running the complete CI suite (including Windows PowerShell 5.1 targets), use Invoke-Build with the InvokeBuild and platyPS modules installed:

Invoke-Build Build           # full build + module assembly + help generation
Invoke-Build TestPS74        # unit tests via build script
Invoke-Build TestE2EPwsh     # E2E tests via build script
Invoke-Build Build -Configuration Release  # required before PRs (enforces XML doc comments)

src/PowerShellEditorServices.Hosting/BuildInfo.cs is auto-generated by the build script and git-ignored for changes. Do not edit it manually.

Architecture

PowerShell Editor Services (PSES) is a Language Server Protocol (LSP) and Debug Adapter Protocol (DAP) server for PowerShell, consumed by VS Code and other editors.

Projects

  • src/PowerShellEditorServices (netstandard2.0) — Core library containing all LSP/DAP handlers, services, and the PowerShell execution engine. Namespace: Microsoft.PowerShell.EditorServices.
  • src/PowerShellEditorServices.Hosting (net8.0, net462) — Entry point layer that loads PSES into a PowerShell process via StartEditorServicesCommand. Uses a custom AssemblyLoadContext (PsesLoadContext) on .NET Core to isolate dependencies.
  • module/PowerShellEditorServices/ — The shipped PowerShell module. The build assembles compiled binaries into bin/Core/ (net8.0) and bin/Desktop/ (net462). The module manifest loads the appropriate DLL based on PowerShell edition.

Key Services (registered in PsesServiceCollectionExtensions)

  • PsesInternalHost — The central PowerShell execution host. Also implements IRunspaceContext and IInternalPowerShellExecutionService.
  • WorkspaceService — Manages open documents and workspace files.
  • SymbolsService — Provides symbol navigation (go-to-definition, find references).
  • AnalysisService — Integrates PSScriptAnalyzer for real-time diagnostics.
  • ConfigurationService — Manages editor/client settings.
  • ExtensionService — Supports the $psEditor API for editor extensions.

LSP/DAP Handler Pattern

Handlers live under Services/<Feature>/Handlers/ and follow a consistent pattern:

  • Class name: Pses<Feature>Handler, marked internal
  • Inherits from an OmniSharp base class (e.g., CompletionHandlerBase, HoverHandlerBase)
  • Dependencies injected via constructor (ILoggerFactory, services)
  • Overrides CreateRegistrationOptions() and Handle()
  • Uses LspUtils.PowerShellDocumentSelector for document registration

Server Setup

  • PsesLanguageServer — Configures and runs the LSP server using OmniSharp
  • PsesDebugServer — Configures and runs the DAP server
  • Both use Microsoft.Extensions.DependencyInjection for service registration

Conventions

C# Style

  • All files require the copyright header: // Copyright (c) Microsoft Corporation. / // Licensed under the MIT License.
  • .editorconfig enforces many rules as errors, including unused variables, async/threading rules (VSTHRD*), and modern C# idioms (pattern matching, null checks, expression bodies).
  • Roslynator analyzers are enabled for formatting and code quality.
  • Use Microsoft.Extensions.Logging (ILogger<T> via ILoggerFactory) for all logging.

Public API & Binary Compatibility

The public types under Microsoft.PowerShell.EditorServices are not consumed only through PowerShell script. Downstream modules compile against the shipped PSES assemblies and bind to that metadata at build time. The most prominent example is SeeminglyScience/EditorServicesCommandSuite, which references the extension API surface (FileContext, EditorContext, the IFileRange/FilePosition types, ILspCurrentFileContext, IEditorScriptFile, etc.) directly from C#.

Because of that, treat any change to an existing public member as potentially binary breaking, and review for it explicitly before merging:

  • Changing the type of a parameter (even widening a concrete class to an interface it implements, e.g. FileRange -> IFileRange), the return type, the parameter count/order, or renaming/removing a public member is source-compatible at most but binary-breaking. The method's signature/metadata token changes, so a precompiled caller throws MissingMethodException at runtime even though it would recompile cleanly.
  • When you need a wider or different signature, add an overload instead of editing the existing one. Keep the original signature in place and have it delegate to the new implementation so existing binaries keep resolving. Cast as needed to pick the new overload from the old body (e.g. Foo((IFileRange)range)).
  • Add a regression test that binds to the old, concrete signature (declare the argument as the original parameter type, not the widened one) so overload resolution to the compatibility shim is actually exercised.
  • If a breaking change is genuinely unavoidable, call it out in the PR description as a binary breaking change so maintainers can weigh it and coordinate a downstream release.

Testing

  • Framework: xUnit with Xunit.SkippableFact for conditionally skipped tests.
  • Host setup: Use PsesHostFactory.Create(loggerFactory) to get an isolated PsesInternalHost for testing. Tests implement IAsyncLifetime for async setup/teardown.
  • Traits: Tests use [Trait("Category", "...")] for filtering (e.g., "Completions", "Symbols").
  • Fixtures: Test PowerShell scripts live in test/PowerShellEditorServices.Test/Fixtures/.
  • E2E tests are in a separate project (PowerShellEditorServices.Test.E2E) and test the full LSP client-server interaction.

Multi-targeting

The core library targets netstandard2.0 for compatibility with both .NET Core and .NET Framework. The hosting project and tests dual-target net8.0 and net462 (Windows PowerShell 5.1). Non-Windows platforms skip net462 targets.

Pull Request Labels

Every pull request must be labeled before it is opened so it is triaged correctly and lands in the right changelog section.

Each PR requires:

  • At least one Area-* label describing the part of the codebase it touches (e.g. Area-Debugging, Area-Language Server, Area-Workspaces, Area-Documentation). This is used for triage and filtering.
  • Exactly one Issue-* label describing the kind of change:
    • Issue-Bug — a bug fix.
    • Issue-Enhancement — a new feature or changed behavior.
    • Issue-Performance — a performance improvement.

The Issue-* label is not optional: GitHub's auto-generated release notes use it to pick the changelog category. See .github/release.yml for the authoritative mapping (Issue-Enhancement → "Enhancements & Features ✨", Issue-Bug → "Squashed Bugs 🐛"). Any PR without an Issue-* label falls through the "*" catch-all into "Other Changes 🙏" and is silently miscategorized, so always set one correctly.

Additionally:

  • Add the relevant OS-* label (OS-Windows, OS-macOS, OS-Linux) when a change is platform-specific.
  • Use the Ignore label only for changes that should be excluded from the release notes entirely (e.g. pure CI, test, or docs chores the maintainers do not want in the changelog). .github/release.yml excludes this label from the changelog.

The full, authoritative set of labels drifts over time — do not hard-code it here. List the current labels with gh label list --repo PowerShell/PowerShellEditorServices or the repo's Labels page and pick the closest matches.