Skip to content

Commit 5ee324a

Browse files
Copilotanthonykim1
andcommitted
Implement dynamic modifier key detection for Native REPL link
Co-authored-by: anthonykim1 <[email protected]>
1 parent 386f592 commit 5ee324a

File tree

2 files changed

+161
-7
lines changed

2 files changed

+161
-7
lines changed

src/client/terminals/pythonStartupLinkProvider.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,38 @@ import {
99
} from 'vscode';
1010
import { executeCommand } from '../common/vscodeApis/commandApis';
1111
import { registerTerminalLinkProvider } from '../common/vscodeApis/windowApis';
12+
import { getConfiguration } from '../common/vscodeApis/workspaceApis';
1213
import { Repl } from '../common/utils/localize';
1314

1415
interface CustomTerminalLink extends TerminalLink {
1516
command: string;
1617
}
1718

19+
/**
20+
* Gets the appropriate modifier key text for the Native REPL link based on the
21+
* editor.multiCursorModifier setting and platform.
22+
*/
23+
function getModifierKeyText(): string {
24+
const editorConfig = getConfiguration('editor');
25+
const multiCursorModifier = editorConfig.get<string>('multiCursorModifier', 'alt');
26+
27+
if (multiCursorModifier === 'ctrlCmd') {
28+
// When multiCursorModifier is ctrlCmd, links use Alt/Option
29+
return process.platform === 'darwin' ? 'Option' : 'Alt';
30+
} else {
31+
// Default behavior: multiCursorModifier is alt, links use Ctrl/Cmd
32+
return process.platform === 'darwin' ? 'Cmd' : 'Ctrl';
33+
}
34+
}
35+
1836
export class CustomTerminalLinkProvider implements TerminalLinkProvider<CustomTerminalLink> {
1937
provideTerminalLinks(
2038
context: TerminalLinkContext,
2139
_token: CancellationToken,
2240
): ProviderResult<CustomTerminalLink[]> {
2341
const links: CustomTerminalLink[] = [];
24-
let expectedNativeLink;
25-
26-
if (process.platform === 'darwin') {
27-
expectedNativeLink = 'Cmd click to launch VS Code Native REPL';
28-
} else {
29-
expectedNativeLink = 'Ctrl click to launch VS Code Native REPL';
30-
}
42+
const modifierKey = getModifierKeyText();
43+
const expectedNativeLink = `${modifierKey} click to launch VS Code Native REPL`;
3144

3245
if (context.line.includes(expectedNativeLink)) {
3346
links.push({

src/test/terminals/shellIntegration/pythonStartup.test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => {
5050

5151
pythonConfig = TypeMoq.Mock.ofType<WorkspaceConfiguration>();
5252
editorConfig = TypeMoq.Mock.ofType<WorkspaceConfiguration>();
53+
54+
// Set up default behavior for editor config
55+
editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'alt');
56+
5357
getConfigurationStub.callsFake((section: string) => {
5458
if (section === 'python') {
5559
return pythonConfig.object;
@@ -63,6 +67,9 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => {
6367

6468
teardown(() => {
6569
sinon.restore();
70+
// Reset editorConfig mock to default behavior for next test
71+
editorConfig.reset();
72+
editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'alt');
6673
});
6774

6875
test('Verify createDirectory is called when shell integration is enabled', async () => {
@@ -200,6 +207,73 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => {
200207
);
201208
}
202209
});
210+
211+
test('Mac - Verify provideTerminalLinks returns links with Option modifier when multiCursorModifier is ctrlCmd', () => {
212+
// Mock the editor configuration to return ctrlCmd
213+
editorConfig.reset();
214+
editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd');
215+
216+
const provider = new CustomTerminalLinkProvider();
217+
const context: TerminalLinkContext = {
218+
line: 'Some random string with Option click to launch VS Code Native REPL',
219+
terminal: {} as Terminal,
220+
};
221+
const token: CancellationToken = {
222+
isCancellationRequested: false,
223+
onCancellationRequested: new EventEmitter<unknown>().event,
224+
};
225+
226+
const links = provider.provideTerminalLinks(context, token);
227+
228+
assert.isNotNull(links, 'Expected links to be not undefined');
229+
assert.isArray(links, 'Expected links to be an array');
230+
assert.isNotEmpty(links, 'Expected links to be not empty');
231+
232+
if (Array.isArray(links)) {
233+
assert.equal(
234+
links[0].startIndex,
235+
context.line.indexOf('Option click to launch VS Code Native REPL'),
236+
'start index should match',
237+
);
238+
assert.equal(
239+
links[0].length,
240+
'Option click to launch VS Code Native REPL'.length,
241+
'Match expected length',
242+
);
243+
}
244+
});
245+
246+
test('Mac - Verify provideTerminalLinks returns links with Cmd modifier when multiCursorModifier is default (alt)', () => {
247+
// This test verifies the default behavior when multiCursorModifier is 'alt'
248+
const provider = new CustomTerminalLinkProvider();
249+
const context: TerminalLinkContext = {
250+
line: 'Some random string with Cmd click to launch VS Code Native REPL',
251+
terminal: {} as Terminal,
252+
};
253+
const token: CancellationToken = {
254+
isCancellationRequested: false,
255+
onCancellationRequested: new EventEmitter<unknown>().event,
256+
};
257+
258+
const links = provider.provideTerminalLinks(context, token);
259+
260+
assert.isNotNull(links, 'Expected links to be not undefined');
261+
assert.isArray(links, 'Expected links to be an array');
262+
assert.isNotEmpty(links, 'Expected links to be not empty');
263+
264+
if (Array.isArray(links)) {
265+
assert.equal(
266+
links[0].startIndex,
267+
context.line.indexOf('Cmd click to launch VS Code Native REPL'),
268+
'start index should match',
269+
);
270+
assert.equal(
271+
links[0].length,
272+
'Cmd click to launch VS Code Native REPL'.length,
273+
'Match expected length',
274+
);
275+
}
276+
});
203277
}
204278
if (process.platform !== 'darwin') {
205279
test('Windows/Linux - Verify provideTerminalLinks returns links when context.line contains expectedNativeLink', () => {
@@ -242,6 +316,73 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => {
242316
);
243317
}
244318
});
319+
320+
test('Windows/Linux - Verify provideTerminalLinks returns links with Alt modifier when multiCursorModifier is ctrlCmd', () => {
321+
// Mock the editor configuration to return ctrlCmd
322+
editorConfig.reset();
323+
editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd');
324+
325+
const provider = new CustomTerminalLinkProvider();
326+
const context: TerminalLinkContext = {
327+
line: 'Some random string with Alt click to launch VS Code Native REPL',
328+
terminal: {} as Terminal,
329+
};
330+
const token: CancellationToken = {
331+
isCancellationRequested: false,
332+
onCancellationRequested: new EventEmitter<unknown>().event,
333+
};
334+
335+
const links = provider.provideTerminalLinks(context, token);
336+
337+
assert.isNotNull(links, 'Expected links to be not undefined');
338+
assert.isArray(links, 'Expected links to be an array');
339+
assert.isNotEmpty(links, 'Expected links to be not empty');
340+
341+
if (Array.isArray(links)) {
342+
assert.equal(
343+
links[0].startIndex,
344+
context.line.indexOf('Alt click to launch VS Code Native REPL'),
345+
'start index should match',
346+
);
347+
assert.equal(
348+
links[0].length,
349+
'Alt click to launch VS Code Native REPL'.length,
350+
'Match expected length',
351+
);
352+
}
353+
});
354+
355+
test('Windows/Linux - Verify provideTerminalLinks returns links with Ctrl modifier when multiCursorModifier is default (alt)', () => {
356+
// This test verifies the default behavior when multiCursorModifier is 'alt'
357+
const provider = new CustomTerminalLinkProvider();
358+
const context: TerminalLinkContext = {
359+
line: 'Some random string with Ctrl click to launch VS Code Native REPL',
360+
terminal: {} as Terminal,
361+
};
362+
const token: CancellationToken = {
363+
isCancellationRequested: false,
364+
onCancellationRequested: new EventEmitter<unknown>().event,
365+
};
366+
367+
const links = provider.provideTerminalLinks(context, token);
368+
369+
assert.isNotNull(links, 'Expected links to be not undefined');
370+
assert.isArray(links, 'Expected links to be an array');
371+
assert.isNotEmpty(links, 'Expected links to be not empty');
372+
373+
if (Array.isArray(links)) {
374+
assert.equal(
375+
links[0].startIndex,
376+
context.line.indexOf('Ctrl click to launch VS Code Native REPL'),
377+
'start index should match',
378+
);
379+
assert.equal(
380+
links[0].length,
381+
'Ctrl click to launch VS Code Native REPL'.length,
382+
'Match expected length',
383+
);
384+
}
385+
});
245386
}
246387

247388
test('Verify provideTerminalLinks returns no links when context.line does not contain expectedNativeLink', () => {

0 commit comments

Comments
 (0)