Skip to content

fix(vs): correct TFM and VSSDK interop DLL path for CI build - net8.0 → net8.0-windows in integration test project so the Microsoft.VisualStudio.Sdk.TestFramework.Xunit 17.11 package resolves its net8.0-windows assets (plain net8.0 fell back to a netstandard2.0 stub that omits VsFact / GlobalServiceProvider). - Fix HintPath for Microsoft.Internal.VisualStudio.Interop.dll in both projects; previous path (tools\vssdk\bin\lib\) does not exist in the VSSDK.BuildTools NuGet package. Correct path for the test project is tools\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0\ via $(NuGetPackageRoot); for the VSIX project use $(VsSDKInstall) which the already-imported Microsoft.VsSDK.targets sets to that same VisualStudioIntegration folder. https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw - #12

Merged
PhysShell merged 5 commits into
mainfrom
claude/snipper-docs-lint-scaffold-pTNoL
Jun 4, 2026

Conversation

@PhysShell

Copy link
Copy Markdown
Owner

No description provided.

claude added 3 commits June 3, 2026 12:37
…, restore tests

## Why syntax highlighting / autocomplete broke

SnipperLanguageServerProvider used VS.Extensibility's LanguageServerProvider
(VSEXTPREVIEW_LSP — explicitly a preview API). In VS 17.14 this API routes
language-service requests for **/*.cs through snipper-lsp *instead of*
merging with Roslyn, so Roslyn semantic tokens and IntelliSense disappeared.

## Fixes

**ILanguageClient (SnipperLanguageServerProvider.cs rewritten)**
Replace LanguageServerProvider with the stable VSSDK ILanguageClient API
([ContentType("CSharp")][Export(typeof(ILanguageClient))]). VS merges
snipper-lsp's completions with Roslyn's — Roslyn semantic highlighting is
unaffected. Removes VSEXTPREVIEW_LSP noWarn; drops Nerdbank.Streams and
System.IO.Pipelines from the main project (no longer needed).

**Commands (SnipperCommands.cs + SnipperLspRpc.cs)**
workspace/executeCommand in snipper-lsp is stateless (just looks up a rule
by name — no document context). Commands now open a short-lived per-invocation
StreamJsonRpc connection: initialize → initialized → workspace/executeCommand
→ shutdown → exit. The missing Extensibility.LanguageServer() API was
fabricated in the original scaffold and never existed in any SDK version.
Adds SnipperLspRpc.cs with the extracted RPC helper (testable in isolation).

**TabstopInserter.cs** — restore IVsExpansionView / temp-snippet path
(the buggy commit had replaced it with a plain ReplaceTextOnLine stub).

**Tests**
- SnipperCommandRpcTests: 3 [Fact] tests — fake in-memory LSP server via
  FullDuplexStream.CreatePair(); verifies initialize is sent first, correct
  body is returned, null is handled cleanly.
- SnipperLanguageClientTests: 4 [Fact] tests — ActivateAsync null-path,
  StartAsync event firing, no-subscriber guard, OnServerInitializeFailed.
- TabstopInserterTests restored with GlobalServiceProvider + [VsFact]
  and VS SDK 17.14 interface signatures (TextSelMode, uint dwFlags).
- LspSnippetConverterVsTests / SnipperBinaryLocatorTests /
  SnipperOptionsPageTests restored from pre-breakage commit.
- IntegrationTests.csproj: re-adds Sdk.TestFramework 17.11, adds
  StreamJsonRpc + Nerdbank.Streams with runtime assets, links new files.

https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw
Three independent issues caused both vs-integration-tests and vsix-package-vs to fail:

1. Microsoft.VisualStudio.Sdk.TestFramework.Xunit 17.11+ ships net8.0 assets only —
   the net472 test project couldn't resolve the Xunit sub-namespace.
   Fix: change TargetFramework net472 → net8.0 and drop the net472-only binding-redirect settings.

2. Microsoft.Internal.VisualStudio.Interop (IXMLDOMNode, IVsExpansionView,
   IVsXMLMemberIndexService, etc.) was not auto-referenced in either project.
   Fix: add explicit <Reference> with HintPath to both the VSIX project and the
   test project; add Microsoft.VSSDK.BuildTools to the test project so the DLL
   is restored to the NuGet cache before the HintPath is evaluated.

3. PlainTextViewStub was sealed, preventing ExpansionViewStub from deriving from it.
   Fix: remove the sealed modifier.

Also adds SnipperPackage.cs to the test project's linked sources so that
SnipperLanguageClient (SnipperLanguageServerProvider.cs) compiles.

https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw
- net8.0 → net8.0-windows in integration test project so the
  Microsoft.VisualStudio.Sdk.TestFramework.Xunit 17.11 package resolves
  its net8.0-windows assets (plain net8.0 fell back to a netstandard2.0
  stub that omits VsFact / GlobalServiceProvider).
- Fix HintPath for Microsoft.Internal.VisualStudio.Interop.dll in both
  projects; previous path (tools\vssdk\bin\lib\) does not exist in the
  VSSDK.BuildTools NuGet package.  Correct path for the test project is
  tools\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0\ via
  $(NuGetPackageRoot); for the VSIX project use $(VsSDKInstall) which
  the already-imported Microsoft.VsSDK.targets sets to that same
  VisualStudioIntegration folder.

https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 133cf9bc66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +26 to +27
var handler = new HeaderDelimitedMessageHandler(
serverOutput, serverInput, new JsonMessageFormatter());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Send RPC requests to the server input stream

When a VS command runs against the real snipper-lsp process, these streams are separate: StandardInput is the stream the client must write to and StandardOutput is the stream it must read from. HeaderDelimitedMessageHandler(Stream?, Stream?, ...) treats the first stream as the sending stream and the second as the receiving stream, so the current call tries to write requests to StandardOutput and read responses from StandardInput, preventing the per-command RPC path from completing. The in-memory tests pass the same duplex stream for both parameters, which masks this; swap the arguments here (or pass input as sending, output as receiving).

Useful? React with 👍 / 👎.

claude added 2 commits June 3, 2026 18:08
HeaderDelimitedMessageHandler(sending, receiving, formatter) — the first
argument is the stream the client writes to (serverInput / StandardInput)
and the second is the stream the client reads from (serverOutput /
StandardOutput).  The previous order sent requests to StandardOutput and
read responses from StandardInput, so no per-command RPC call could
ever complete against a real snipper-lsp process.

https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw
All three tests were passing the same FullDuplexStream for both the
serverOutput and serverInput parameters of ExecuteCommandAsync, which
meant swapping the HeaderDelimitedMessageHandler arguments had no
observable effect — the stream-swap bug was completely masked.

Replace with two System.IO.Pipelines.Pipe objects (client→server and
server→client) so that read and write halves are physically separate
streams.  With directed pipes, passing the wrong stream as the sending
or receiving end immediately breaks the JSON-RPC handshake, making the
tests a genuine regression guard for the argument order.

Nerdbank.Streams is no longer referenced and is removed from the csproj.

https://claude.ai/code/session_01VRbhF1wSDh9FXKajAPUyqw
@PhysShell

Copy link
Copy Markdown
Owner Author

The @codex, whatcha say now?

@chatgpt-codex-connector

Copy link
Copy Markdown

Assessment

The review feedback appears to be addressed already on the current PR branch. SnipperLspRpc.ExecuteCommandAsync takes serverOutput first and serverInput second, then constructs HeaderDelimitedMessageHandler with serverInput as the sending stream and serverOutput as the receiving stream. That matches the StreamJsonRpc constructor contract: first stream sends/transmits, second stream receives.

The tests also now use two separate unidirectional pipes rather than a single duplex stream, specifically to catch swapped stream arguments instead of masking them. The helper names the streams so the client reads from serverOutput, writes to serverInput, the fake server reads from serverRead, and writes to serverWrite.

I did not make code changes, commit, or open a new PR because the requested fix is already present in the checked-out branch.

Reference checked: StreamJsonRpc’s HeaderDelimitedMessageHandler(Stream? sendingStream, Stream? receivingStream, ...) documentation describes the first stream as transmitting/sending and the second as receiving: https://microsoft.github.io/vs-streamjsonrpc/api/StreamJsonRpc.HeaderDelimitedMessageHandler.html

Testing / Checks

  • ✅ git status --short — no local changes were present.
  • ✅ rg -n "HeaderDelimitedMessageHandler|SnipperLspRpc|StandardInput|StandardOutput" extensions/snipper-vs -S — confirmed the relevant call sites and tests.
  • ⚠️ dotnet test extensions/snipper-vs/Snipper.VisualStudio.IntegrationTests/Snipper.VisualStudio.IntegrationTests.csproj --no-restore — could not run because dotnet is not installed in this environment.

View task →

@PhysShell
PhysShell merged commit 353d083 into main Jun 4, 2026
32 of 38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants