Skip to content

Commit e7e8dd2

Browse files
committed
Fixed an issue where commands could be run in the same terminal if the terminal name was the same.
Terminals were incorrectly reused when customTerminalName was identical - Always create new terminal when customTerminalName is configured - Use command as key for reuse when no customTerminalName - Add tests for terminal creation behavior fix #58
1 parent 858be49 commit e7e8dd2

File tree

3 files changed

+79
-12
lines changed

3 files changed

+79
-12
lines changed

src/extension/__mocks__/vscode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module.exports = {
2323
showErrorMessage: jest.fn(),
2424
showInformationMessage: jest.fn(),
2525
createTreeView: jest.fn(),
26+
createTerminal: jest.fn(),
2627
},
2728
commands: {
2829
registerCommand: jest.fn(),

src/extension/src/terminal-manager.test.ts

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { shouldCreateNewTerminal, determineTerminalName } from "./terminal-manager";
1+
import * as vscode from "vscode";
2+
import {
3+
shouldCreateNewTerminal,
4+
determineTerminalName,
5+
TerminalManager,
6+
} from "./terminal-manager";
27

38
describe("terminal-manager", () => {
49
describe("shouldCreateNewTerminal", () => {
@@ -52,4 +57,57 @@ describe("terminal-manager", () => {
5257
expect(result).toBe("ls");
5358
});
5459
});
60+
61+
describe("TerminalManager", () => {
62+
let manager: TerminalManager;
63+
let mockTerminal: vscode.Terminal;
64+
65+
beforeEach(() => {
66+
manager = TerminalManager.create();
67+
mockTerminal = {
68+
dispose: jest.fn(),
69+
exitStatus: undefined,
70+
sendText: jest.fn(),
71+
show: jest.fn(),
72+
} as any;
73+
74+
jest.spyOn(vscode.window, "createTerminal").mockReturnValue(mockTerminal);
75+
});
76+
77+
afterEach(() => {
78+
jest.restoreAllMocks();
79+
});
80+
81+
it("should create separate terminals when customTerminalName is set", () => {
82+
manager.executeCommand("npm start", false, "build");
83+
manager.executeCommand("npm test", false, "build");
84+
85+
expect(vscode.window.createTerminal).toHaveBeenCalledTimes(2);
86+
expect(vscode.window.createTerminal).toHaveBeenNthCalledWith(1, "build");
87+
expect(vscode.window.createTerminal).toHaveBeenNthCalledWith(2, "build");
88+
});
89+
90+
it("should create new terminal every time when customTerminalName is set", () => {
91+
manager.executeCommand("npm start", false, "build");
92+
manager.executeCommand("npm start", false, "build");
93+
94+
expect(vscode.window.createTerminal).toHaveBeenCalledTimes(2);
95+
});
96+
97+
it("should reuse terminal for same command without customTerminalName", () => {
98+
manager.executeCommand("npm start", false);
99+
manager.executeCommand("npm start", false);
100+
101+
expect(vscode.window.createTerminal).toHaveBeenCalledTimes(1);
102+
});
103+
104+
it("should create separate terminals for different commands without customTerminalName", () => {
105+
manager.executeCommand("npm start", false);
106+
manager.executeCommand("npm test", false);
107+
108+
expect(vscode.window.createTerminal).toHaveBeenCalledTimes(2);
109+
expect(vscode.window.createTerminal).toHaveBeenNthCalledWith(1, "npm");
110+
expect(vscode.window.createTerminal).toHaveBeenNthCalledWith(2, "npm");
111+
});
112+
});
55113
});

src/extension/src/terminal-manager.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,38 @@ export const determineTerminalName = (
1515
export class TerminalManager {
1616
private terminals = new Map<string, vscode.Terminal>();
1717

18+
static create = (): TerminalManager => new TerminalManager();
19+
20+
dispose = () => {
21+
for (const terminal of this.terminals.values()) {
22+
terminal.dispose();
23+
}
24+
this.terminals.clear();
25+
};
26+
1827
executeCommand: TerminalExecutor = (command, useVsCodeApi = false, customTerminalName) => {
1928
if (useVsCodeApi) {
2029
vscode.commands.executeCommand(command);
2130
return;
2231
}
2332

2433
const terminalName = determineTerminalName(customTerminalName, command);
25-
let terminal = this.terminals.get(terminalName);
34+
35+
if (customTerminalName) {
36+
const terminal = vscode.window.createTerminal(terminalName);
37+
terminal.show();
38+
terminal.sendText(command);
39+
return;
40+
}
41+
42+
let terminal = this.terminals.get(command);
2643

2744
if (shouldCreateNewTerminal(terminal)) {
2845
terminal = vscode.window.createTerminal(terminalName);
29-
this.terminals.set(terminalName, terminal);
46+
this.terminals.set(command, terminal);
3047
}
3148

3249
terminal!.show();
3350
terminal!.sendText(command);
3451
};
35-
36-
dispose = () => {
37-
for (const terminal of this.terminals.values()) {
38-
terminal.dispose();
39-
}
40-
this.terminals.clear();
41-
};
42-
43-
static create = (): TerminalManager => new TerminalManager();
4452
}

0 commit comments

Comments
 (0)