Skip to content

perf: start Windows PowerShell once, directly, to read the clipboard - #119

Merged
kkdev92 merged 1 commit into
mainfrom
perf/windows-clipboard-read
Nov 10, 2026
Merged

kkdev92 merged 1 commit into
mainfrom
perf/windows-clipboard-read

Conversation

@kkdev92

@kkdev92 kkdev92 commented Nov 10, 2026

Copy link
Copy Markdown
Owner

On Windows, reading the clipboard now starts Windows PowerShell once, directly. With PowerShell 7 installed a paste waits noticeably less for it, and the first paste in a window no longer pays for a second start.

Why

Most of the time between the paste key and the path appearing is PowerShell starting. Three things made that longer than it has to be:

  • PowerShell 7 was preferred when it was installed. It takes longer to start than Windows PowerShell, and the clipboard script uses nothing it adds: both load the same .NET clipboard API.
  • The command went through cmd.exe. exec starts a shell to parse a command line that has nothing for a shell to do.
  • The first paste in a window started a PowerShell twice. Once to see that one runs, then again for the read.

Change

  • powershell.exe is tried first and pwsh second. The first that gets through the script is remembered for later reads. A failure of the first moves on to the second, so a machine where only PowerShell 7 works keeps working. A timeout does not move on: waiting out a second one would only make the wait longer.
  • There is no separate check that PowerShell starts. isAvailable() answers from the platform, and the read reports a machine where neither is found: "PowerShell could not be started".
  • PowerShell is started with execFile and an argument array, so there is no shell and no command string.
  • A read that outlives the timeout is reported as a timeout. The old check looked for an error code that a timeout does not set.

The macOS and Linux providers are untouched.

Verification

Verified

  • The steps of npm run verify on Windows ARM64: lint, both type checks, 581 unit and integration tests with the coverage thresholds, and the 13 end-to-end tests in VS Code 1.145.2.

  • The new test file replaces child_process and checks how PowerShell is started: which executable, the argument array, one start for the first paste, the fallback, the timeout. All 11 tests fail on the code before this change.

  • One more test, on Windows only, starts the real powershell.exe with the provider's arguments and expects the script's result line.

  • The win32-arm64 VSIX built from this branch, in an isolated VS Code 1.145.2 on Windows 11 ARM64 with PowerShell 7 installed and a 1786×796 image on the real clipboard. Pasting into a Markdown editor saves the PNG and inserts the link. Pasting with the terminal focused types the path and does not run it. With text on the clipboard nothing is saved and the text is pasted. The same steps on 0.10.0 from the Marketplace give the same results.

  • The time of the clipboard read as the extension logs it, in that setup, with this branch and 0.10.0 in alternating windows, two windows of six pastes each:

    0.10.0 This branch
    First paste in a window 1612 ms, 1807 ms 692 ms, 873 ms
    Later pastes, median 718 ms, 726 ms 440 ms, 461 ms
  • Outside VS Code, the shipped script started the way 0.10.0 starts it and the way this branch starts it, eight runs each, median, on an x64 GitHub-hosted Windows runner with PowerShell 7 installed: 465 ms to 305 ms with text on the clipboard, 527 ms to 362 ms with an image.

Not checked

  • The fallback to PowerShell 7 inside VS Code. The tests cover it with a stand-in for child_process, and pwsh was started with the same argument array outside VS Code. No machine without a working Windows PowerShell was used.
  • An image that an application puts on the clipboard in PNG format. The test image was a bitmap, which takes the script's other branch. The script itself is unchanged.
  • win32-x64 by hand. The x64 numbers above are from a CI runner.
  • PowerShell occasionally takes about two seconds longer to start, with either executable, and this change does not address that. One first paste during the checks took 2.4 s.

🤖 Generated with Claude Code

On Windows a paste waited for PowerShell longer than it needed to, in three
ways. PowerShell 7 was preferred when it was installed, although it takes
longer to start than Windows PowerShell and the script needs nothing it adds.
The command went through cmd.exe. And the first paste in a window started a
PowerShell an extra time, only to see that one runs.

The provider now starts powershell.exe itself, with an argument array, and
lets the read be the check: the first executable that gets through the script
is remembered for later reads. PowerShell 7 is tried when Windows PowerShell
cannot be started or fails, so a machine that relied on it keeps working.
isAvailable() answers from the platform alone. A read that outlives the
timeout is reported as a timeout and does not go on to the other executable;
the old check looked for an error code that a timeout does not set.

macOS and Linux are untouched.

Measured with the script as shipped, eight runs each, median. On an ARM64
laptop with PowerShell 7 installed the read went from 682 ms to 337 ms. On an
x64 hosted CI runner it went from 465 ms to 305 ms with text on the clipboard
and from 527 ms to 362 ms with an image, and the extra start that is gone
took 422 ms.

The new test file replaces child_process and fails on the code before this
change, 11 tests of 11. One more test, on Windows only, starts the real
powershell.exe with the provider's arguments.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@kkdev92
kkdev92 merged commit 56ea71b into main Nov 10, 2026
16 checks passed
@kkdev92
kkdev92 deleted the perf/windows-clipboard-read branch November 10, 2026 08:53
@kkdev92 kkdev92 mentioned this pull request Nov 10, 2026
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.

1 participant