From b2d25c24d8c36de53841f5181b068a55446924e2 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 29 Oct 2025 11:46:45 -0400 Subject: [PATCH 1/4] Fix crash when bsc plugin in worker loads another version of bsc --- src/lsp/worker/WorkerThreadProject.ts | 43 ++++++++++++++++----------- src/lsp/worker/run.ts | 10 +++++++ 2 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 src/lsp/worker/run.ts diff --git a/src/lsp/worker/WorkerThreadProject.ts b/src/lsp/worker/WorkerThreadProject.ts index b409ce2f6..1659462cb 100644 --- a/src/lsp/worker/WorkerThreadProject.ts +++ b/src/lsp/worker/WorkerThreadProject.ts @@ -5,8 +5,6 @@ import { MessageHandler } from './MessageHandler'; import util from '../../util'; import type { LspDiagnostic, ActivateResponse, ProjectConfig } from '../LspProject'; import { type LspProject } from '../LspProject'; -import { isMainThread, parentPort } from 'worker_threads'; -import { WorkerThreadProjectRunner } from './WorkerThreadProjectRunner'; import { WorkerPool } from './WorkerPool'; import type { Hover, MaybePromise, SemanticToken } from '../../interfaces'; import type { DocumentAction, DocumentActionWithStatus } from '../DocumentManager'; @@ -16,29 +14,40 @@ import type { Position, Range, Location, DocumentSymbol, WorkspaceSymbol, CodeAc import type { Logger } from '../../logging'; import { createLogger } from '../../logging'; import * as fsExtra from 'fs-extra'; +import * as path from 'path'; +import { standardizePath as s } from '../../util'; + export const workerPool = new WorkerPool(() => { + //construct the path to the `./run.ts` (or `./run.js`) script in this same directory + const runScriptPath = s`${__dirname}/run${path.extname(__filename)}`; + + // Prepare execArgv for debugging support + const execArgv = []; + + // Add ts-node if we're running TypeScript + if (/\.ts$/i.test(runScriptPath)) { + execArgv.push('--require', 'ts-node/register'); + } + + // Enable debugging for worker threads if the main process is being debugged + // Check if debugging is enabled via execArgv or environment variables + const isDebugging = process.execArgv.some(arg => arg.startsWith('--inspect')) || process.env.NODE_OPTIONS?.includes('--inspect'); + + if (isDebugging) { + // Node.js will automatically assign a unique port for each worker when using --inspect=0 + // This allows VSCode to automatically attach to worker threads + execArgv.push('--inspect=0'); + } + return new Worker( - __filename, + runScriptPath, { - //this needs to align with the same flag in the if statement below - argv: ['--run-worker-thread-project-runner'], - //wire up ts-node if we're running in ts-node - execArgv: /\.ts$/i.test(__filename) - ? ['--require', 'ts-node/register'] - /* istanbul ignore next */ - : undefined + execArgv: execArgv.length > 0 ? execArgv : undefined } ); }); -//if this script is running in a Worker, start the project runner -/* istanbul ignore next */ -if (!isMainThread && process.argv.includes('--run-worker-thread-project-runner')) { - const runner = new WorkerThreadProjectRunner(); - runner.run(parentPort); -} - export class WorkerThreadProject implements LspProject { public constructor( options?: { diff --git a/src/lsp/worker/run.ts b/src/lsp/worker/run.ts new file mode 100644 index 000000000..0a40fdf5a --- /dev/null +++ b/src/lsp/worker/run.ts @@ -0,0 +1,10 @@ +/** + * This script is the entry point for worker threads that run LSP Projects. + * It sets up the WorkerThreadProjectRunner to handle messages from the main thread. + */ +import { parentPort } from 'worker_threads'; +import { WorkerThreadProjectRunner } from './WorkerThreadProjectRunner'; + +// eslint-disable-next-line no-debugger +const runner = new WorkerThreadProjectRunner(); +runner.run(parentPort); From b36662a6702ebd84f0ae851f93ca4aafec250eb3 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Fri, 31 Oct 2025 09:34:11 -0400 Subject: [PATCH 2/4] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/lsp/worker/WorkerThreadProject.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lsp/worker/WorkerThreadProject.ts b/src/lsp/worker/WorkerThreadProject.ts index 1659462cb..55e152e23 100644 --- a/src/lsp/worker/WorkerThreadProject.ts +++ b/src/lsp/worker/WorkerThreadProject.ts @@ -23,7 +23,7 @@ export const workerPool = new WorkerPool(() => { const runScriptPath = s`${__dirname}/run${path.extname(__filename)}`; // Prepare execArgv for debugging support - const execArgv = []; + const execArgv: string[] = []; // Add ts-node if we're running TypeScript if (/\.ts$/i.test(runScriptPath)) { From 65c22a5dd0b9ca657cbee31281bdec65d58ed9d6 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Fri, 31 Oct 2025 09:34:25 -0400 Subject: [PATCH 3/4] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/lsp/worker/run.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lsp/worker/run.ts b/src/lsp/worker/run.ts index 0a40fdf5a..257440b97 100644 --- a/src/lsp/worker/run.ts +++ b/src/lsp/worker/run.ts @@ -7,4 +7,7 @@ import { WorkerThreadProjectRunner } from './WorkerThreadProjectRunner'; // eslint-disable-next-line no-debugger const runner = new WorkerThreadProjectRunner(); +if (!parentPort) { + throw new Error('This script must be run as a worker thread'); +} runner.run(parentPort); From 81bf0a15a2734fe2bfc58971a5229e4ddb489d39 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Fri, 31 Oct 2025 09:34:35 -0400 Subject: [PATCH 4/4] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/lsp/worker/run.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lsp/worker/run.ts b/src/lsp/worker/run.ts index 257440b97..7ea2f5103 100644 --- a/src/lsp/worker/run.ts +++ b/src/lsp/worker/run.ts @@ -5,7 +5,6 @@ import { parentPort } from 'worker_threads'; import { WorkerThreadProjectRunner } from './WorkerThreadProjectRunner'; -// eslint-disable-next-line no-debugger const runner = new WorkerThreadProjectRunner(); if (!parentPort) { throw new Error('This script must be run as a worker thread');