Skip to content

Commit 5caefd6

Browse files
committed
fix: run debugger in terminal shell when shellType is terminal
Fixes #571
1 parent 91c485f commit 5caefd6

File tree

5 files changed

+104
-14
lines changed

5 files changed

+104
-14
lines changed

debug-shims.d.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* eslint-disable ts/method-signature-style */
2+
// https://github.com/microsoft/vscode-js-debug/blob/main/src/typings/vscode-js-debug.d.ts
3+
4+
declare module '@vscode/js-debug' {
5+
import type * as vscode from 'vscode'
6+
7+
/** @see {IExports.registerDebugTerminalOptionsProvider} */
8+
export interface IDebugTerminalOptionsProvider {
9+
/**
10+
* Called when the user creates a JavaScript Debug Terminal. It's called
11+
* with the options js-debug wants to use to create the terminal. It should
12+
* modify and return the options to use in the terminal.
13+
*
14+
* In order to avoid conflicting with existing logic, participants should
15+
* try to modify options in a additive way. For example prefer appending
16+
* to rather than reading and overwriting `options.env.PATH`.
17+
*/
18+
provideTerminalOptions(options: vscode.TerminalOptions): vscode.ProviderResult<vscode.TerminalOptions>
19+
}
20+
21+
/**
22+
* Defines the exports of the `js-debug` extension. Once you have this typings
23+
* file, these can be acquired in your extension using the following code:
24+
*
25+
* ```
26+
* const jsDebugExt = vscode.extensions.getExtension('ms-vscode.js-debug-nightly')
27+
* || vscode.extensions.getExtension('ms-vscode.js-debug');
28+
* await jsDebugExt.activate()
29+
* const jsDebug: import('@vscode/js-debug').IExports = jsDebug.exports;
30+
* ```
31+
*/
32+
export interface IExports {
33+
/**
34+
* Registers a participant used when the user creates a JavaScript Debug Terminal.
35+
*/
36+
registerDebugTerminalOptionsProvider(provider: IDebugTerminalOptionsProvider): vscode.Disposable
37+
}
38+
}

src/api/terminal.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,24 @@ export async function createVitestTerminalProcess(pkg: VitestPackage): Promise<R
5656
}
5757

5858
export class VitestTerminalProcess implements VitestProcess {
59+
private stopped: Promise<void>
60+
5961
constructor(
6062
public readonly id: number,
6163
private wsProcess: VitestWebSocketProcess,
6264
private readonly terminal: vscode.Terminal,
6365
) {
64-
const disposer = vscode.window.onDidCloseTerminal(async (e) => {
65-
if (e === terminal) {
66-
const exitCode = e.exitStatus?.code
67-
// TODO: have a single emitter, don't reuse ws one
68-
// this event is required for api.dispose() and onUnexpectedExit
69-
wsProcess.ws.emit('exit', exitCode)
70-
disposer.dispose()
71-
}
66+
this.stopped = new Promise((resolve) => {
67+
const disposer = vscode.window.onDidCloseTerminal(async (e) => {
68+
if (e === terminal) {
69+
const exitCode = e.exitStatus?.code
70+
// TODO: have a single emitter, don't reuse ws one
71+
// this event is required for api.dispose() and onUnexpectedExit
72+
wsProcess.ws.emit('exit', exitCode)
73+
disposer.dispose()
74+
resolve()
75+
}
76+
})
7277
})
7378
}
7479

@@ -82,7 +87,11 @@ export class VitestTerminalProcess implements VitestProcess {
8287

8388
close() {
8489
this.wsProcess.close()
85-
this.terminal.dispose()
90+
// send ctrl+c to sigint any running processs (vscode/#108289)
91+
this.terminal.sendText('\x03')
92+
// and then destroy it on the next event loop tick
93+
setTimeout(() => this.terminal.dispose(), 1)
94+
return this.stopped
8695
}
8796

8897
on(event: string, listener: (...args: any[]) => void) {

src/debug/api.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,21 @@ export async function debugTests(
3737

3838
const debugConfig = {
3939
__name: 'Vitest',
40-
type: 'pwa-node',
40+
type: config.shellType === 'terminal' ? 'node-terminal' : 'pwa-node',
4141
request: 'launch',
4242
name: 'Debug Tests',
4343
autoAttachChildProcesses: true,
4444
skipFiles: config.debugExclude,
4545
smartStep: true,
46-
runtimeArgs,
47-
runtimeExecutable,
48-
program: workerPath,
46+
...(config.shellType === 'terminal'
47+
? {
48+
command: `${runtimeExecutable} ${workerPath}`,
49+
}
50+
: {
51+
program: workerPath,
52+
runtimeArgs,
53+
runtimeExecutable,
54+
}),
4955
cwd: pkg.cwd,
5056
env: {
5157
...process.env,

src/extension.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class VitestExtension {
3939

4040
private disposables: vscode.Disposable[] = []
4141

42+
/** @internal */
43+
_debugDisposable: vscode.Disposable | undefined
44+
4245
constructor() {
4346
log.info(`[v${version}] Vitest extension is activated because Vitest is installed or there is a Vite/Vitest config file in the workspace.`)
4447

@@ -206,6 +209,8 @@ class VitestExtension {
206209
}
207210
debugProfile.tag = api.tag
208211
debugProfile.runHandler = async (request, token) => {
212+
await this.registerDebugOptions()
213+
209214
await debugTests(
210215
this.testController,
211216
this.testTree,
@@ -400,6 +405,38 @@ class VitestExtension {
400405
}
401406
}
402407

408+
async registerDebugOptions() {
409+
if (this._debugDisposable) {
410+
return
411+
}
412+
const config = getConfig()
413+
if (config.shellType !== 'terminal') {
414+
return
415+
}
416+
try {
417+
const jsDebugExt = vscode.extensions.getExtension('ms-vscode.js-debug-nightly') || vscode.extensions.getExtension('ms-vscode.js-debug')
418+
await jsDebugExt?.activate()
419+
const jsDebug: import('@vscode/js-debug').IExports = jsDebugExt?.exports
420+
421+
if (jsDebug) {
422+
this._debugDisposable = jsDebug.registerDebugTerminalOptionsProvider({
423+
provideTerminalOptions(options) {
424+
options.shellArgs = getConfig().terminalShellArgs
425+
options.shellPath = getConfig().terminalShellPath
426+
return options
427+
},
428+
})
429+
this.disposables.push(this._debugDisposable)
430+
}
431+
else {
432+
log.error('Failed to connect to the debug extension. Debugger will open a terminal window.')
433+
}
434+
}
435+
catch (err) {
436+
log.error('Cannot create debug options provider.', err)
437+
}
438+
}
439+
403440
async dispose() {
404441
this.api?.dispose()
405442
this.testTree.dispose()

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"extends": ["./tsconfig.base.json"],
3-
"include": ["src"]
3+
"include": ["src", "./debug-shims.d.ts"]
44
}

0 commit comments

Comments
 (0)