From 386f592a1bb4e0386150f940aadeb355732b80a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Jun 2025 04:03:54 +0000 Subject: [PATCH 1/4] Initial plan for issue From 5ee324a647343ff518befc0891da7d86ace872e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Jun 2025 04:18:47 +0000 Subject: [PATCH 2/4] Implement dynamic modifier key detection for Native REPL link Co-authored-by: anthonykim1 <62267334+anthonykim1@users.noreply.github.com> --- .../terminals/pythonStartupLinkProvider.ts | 27 +++- .../shellIntegration/pythonStartup.test.ts | 141 ++++++++++++++++++ 2 files changed, 161 insertions(+), 7 deletions(-) diff --git a/src/client/terminals/pythonStartupLinkProvider.ts b/src/client/terminals/pythonStartupLinkProvider.ts index aba1270f1412..d39a00768ad4 100644 --- a/src/client/terminals/pythonStartupLinkProvider.ts +++ b/src/client/terminals/pythonStartupLinkProvider.ts @@ -9,25 +9,38 @@ import { } from 'vscode'; import { executeCommand } from '../common/vscodeApis/commandApis'; import { registerTerminalLinkProvider } from '../common/vscodeApis/windowApis'; +import { getConfiguration } from '../common/vscodeApis/workspaceApis'; import { Repl } from '../common/utils/localize'; interface CustomTerminalLink extends TerminalLink { command: string; } +/** + * Gets the appropriate modifier key text for the Native REPL link based on the + * editor.multiCursorModifier setting and platform. + */ +function getModifierKeyText(): string { + const editorConfig = getConfiguration('editor'); + const multiCursorModifier = editorConfig.get('multiCursorModifier', 'alt'); + + if (multiCursorModifier === 'ctrlCmd') { + // When multiCursorModifier is ctrlCmd, links use Alt/Option + return process.platform === 'darwin' ? 'Option' : 'Alt'; + } else { + // Default behavior: multiCursorModifier is alt, links use Ctrl/Cmd + return process.platform === 'darwin' ? 'Cmd' : 'Ctrl'; + } +} + export class CustomTerminalLinkProvider implements TerminalLinkProvider { provideTerminalLinks( context: TerminalLinkContext, _token: CancellationToken, ): ProviderResult { const links: CustomTerminalLink[] = []; - let expectedNativeLink; - - if (process.platform === 'darwin') { - expectedNativeLink = 'Cmd click to launch VS Code Native REPL'; - } else { - expectedNativeLink = 'Ctrl click to launch VS Code Native REPL'; - } + const modifierKey = getModifierKeyText(); + const expectedNativeLink = `${modifierKey} click to launch VS Code Native REPL`; if (context.line.includes(expectedNativeLink)) { links.push({ diff --git a/src/test/terminals/shellIntegration/pythonStartup.test.ts b/src/test/terminals/shellIntegration/pythonStartup.test.ts index 45535d0ceecc..c1edc0c5622d 100644 --- a/src/test/terminals/shellIntegration/pythonStartup.test.ts +++ b/src/test/terminals/shellIntegration/pythonStartup.test.ts @@ -50,6 +50,10 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { pythonConfig = TypeMoq.Mock.ofType(); editorConfig = TypeMoq.Mock.ofType(); + + // Set up default behavior for editor config + editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'alt'); + getConfigurationStub.callsFake((section: string) => { if (section === 'python') { return pythonConfig.object; @@ -63,6 +67,9 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { teardown(() => { sinon.restore(); + // Reset editorConfig mock to default behavior for next test + editorConfig.reset(); + editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'alt'); }); test('Verify createDirectory is called when shell integration is enabled', async () => { @@ -200,6 +207,73 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { ); } }); + + test('Mac - Verify provideTerminalLinks returns links with Option modifier when multiCursorModifier is ctrlCmd', () => { + // Mock the editor configuration to return ctrlCmd + editorConfig.reset(); + editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd'); + + const provider = new CustomTerminalLinkProvider(); + const context: TerminalLinkContext = { + line: 'Some random string with Option click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + const token: CancellationToken = { + isCancellationRequested: false, + onCancellationRequested: new EventEmitter().event, + }; + + const links = provider.provideTerminalLinks(context, token); + + assert.isNotNull(links, 'Expected links to be not undefined'); + assert.isArray(links, 'Expected links to be an array'); + assert.isNotEmpty(links, 'Expected links to be not empty'); + + if (Array.isArray(links)) { + assert.equal( + links[0].startIndex, + context.line.indexOf('Option click to launch VS Code Native REPL'), + 'start index should match', + ); + assert.equal( + links[0].length, + 'Option click to launch VS Code Native REPL'.length, + 'Match expected length', + ); + } + }); + + test('Mac - Verify provideTerminalLinks returns links with Cmd modifier when multiCursorModifier is default (alt)', () => { + // This test verifies the default behavior when multiCursorModifier is 'alt' + const provider = new CustomTerminalLinkProvider(); + const context: TerminalLinkContext = { + line: 'Some random string with Cmd click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + const token: CancellationToken = { + isCancellationRequested: false, + onCancellationRequested: new EventEmitter().event, + }; + + const links = provider.provideTerminalLinks(context, token); + + assert.isNotNull(links, 'Expected links to be not undefined'); + assert.isArray(links, 'Expected links to be an array'); + assert.isNotEmpty(links, 'Expected links to be not empty'); + + if (Array.isArray(links)) { + assert.equal( + links[0].startIndex, + context.line.indexOf('Cmd click to launch VS Code Native REPL'), + 'start index should match', + ); + assert.equal( + links[0].length, + 'Cmd click to launch VS Code Native REPL'.length, + 'Match expected length', + ); + } + }); } if (process.platform !== 'darwin') { test('Windows/Linux - Verify provideTerminalLinks returns links when context.line contains expectedNativeLink', () => { @@ -242,6 +316,73 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { ); } }); + + test('Windows/Linux - Verify provideTerminalLinks returns links with Alt modifier when multiCursorModifier is ctrlCmd', () => { + // Mock the editor configuration to return ctrlCmd + editorConfig.reset(); + editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd'); + + const provider = new CustomTerminalLinkProvider(); + const context: TerminalLinkContext = { + line: 'Some random string with Alt click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + const token: CancellationToken = { + isCancellationRequested: false, + onCancellationRequested: new EventEmitter().event, + }; + + const links = provider.provideTerminalLinks(context, token); + + assert.isNotNull(links, 'Expected links to be not undefined'); + assert.isArray(links, 'Expected links to be an array'); + assert.isNotEmpty(links, 'Expected links to be not empty'); + + if (Array.isArray(links)) { + assert.equal( + links[0].startIndex, + context.line.indexOf('Alt click to launch VS Code Native REPL'), + 'start index should match', + ); + assert.equal( + links[0].length, + 'Alt click to launch VS Code Native REPL'.length, + 'Match expected length', + ); + } + }); + + test('Windows/Linux - Verify provideTerminalLinks returns links with Ctrl modifier when multiCursorModifier is default (alt)', () => { + // This test verifies the default behavior when multiCursorModifier is 'alt' + const provider = new CustomTerminalLinkProvider(); + const context: TerminalLinkContext = { + line: 'Some random string with Ctrl click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + const token: CancellationToken = { + isCancellationRequested: false, + onCancellationRequested: new EventEmitter().event, + }; + + const links = provider.provideTerminalLinks(context, token); + + assert.isNotNull(links, 'Expected links to be not undefined'); + assert.isArray(links, 'Expected links to be an array'); + assert.isNotEmpty(links, 'Expected links to be not empty'); + + if (Array.isArray(links)) { + assert.equal( + links[0].startIndex, + context.line.indexOf('Ctrl click to launch VS Code Native REPL'), + 'start index should match', + ); + assert.equal( + links[0].length, + 'Ctrl click to launch VS Code Native REPL'.length, + 'Match expected length', + ); + } + }); } test('Verify provideTerminalLinks returns no links when context.line does not contain expectedNativeLink', () => { From 63b5abd83f556b575b18ffc195bb21beb66990d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Jun 2025 04:21:26 +0000 Subject: [PATCH 3/4] Add comprehensive tests for configuration adaptation Co-authored-by: anthonykim1 <62267334+anthonykim1@users.noreply.github.com> --- .../shellIntegration/pythonStartup.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/terminals/shellIntegration/pythonStartup.test.ts b/src/test/terminals/shellIntegration/pythonStartup.test.ts index c1edc0c5622d..514bbb86d5e0 100644 --- a/src/test/terminals/shellIntegration/pythonStartup.test.ts +++ b/src/test/terminals/shellIntegration/pythonStartup.test.ts @@ -385,6 +385,40 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { }); } + test('Verify provideTerminalLinks adapts to configuration changes', () => { + const provider = new CustomTerminalLinkProvider(); + + // Test with default setting (alt) + const context1: TerminalLinkContext = { + line: 'Some random string with Ctrl click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + const token: CancellationToken = { + isCancellationRequested: false, + onCancellationRequested: new EventEmitter().event, + }; + + let links = provider.provideTerminalLinks(context1, token); + assert.isNotEmpty(links, 'Expected links with Ctrl modifier when setting is alt'); + + // Change configuration to ctrlCmd + editorConfig.reset(); + editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd'); + + // Test with changed setting (ctrlCmd) - should now look for Alt + const context2: TerminalLinkContext = { + line: 'Some random string with Alt click to launch VS Code Native REPL', + terminal: {} as Terminal, + }; + + links = provider.provideTerminalLinks(context2, token); + assert.isNotEmpty(links, 'Expected links with Alt modifier when setting is ctrlCmd'); + + // Verify the old Ctrl link no longer works + links = provider.provideTerminalLinks(context1, token); + assert.isEmpty(links, 'Expected no links with Ctrl modifier when setting is ctrlCmd'); + }); + test('Verify provideTerminalLinks returns no links when context.line does not contain expectedNativeLink', () => { const provider = new CustomTerminalLinkProvider(); const context: TerminalLinkContext = { From ee56831617a0b84eac6ce223893612152c9bf549 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Jun 2025 04:22:48 +0000 Subject: [PATCH 4/4] Apply prettier formatting --- src/client/terminals/pythonStartupLinkProvider.ts | 4 ++-- .../terminals/shellIntegration/pythonStartup.test.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/client/terminals/pythonStartupLinkProvider.ts b/src/client/terminals/pythonStartupLinkProvider.ts index d39a00768ad4..1f15fce34b60 100644 --- a/src/client/terminals/pythonStartupLinkProvider.ts +++ b/src/client/terminals/pythonStartupLinkProvider.ts @@ -17,13 +17,13 @@ interface CustomTerminalLink extends TerminalLink { } /** - * Gets the appropriate modifier key text for the Native REPL link based on the + * Gets the appropriate modifier key text for the Native REPL link based on the * editor.multiCursorModifier setting and platform. */ function getModifierKeyText(): string { const editorConfig = getConfiguration('editor'); const multiCursorModifier = editorConfig.get('multiCursorModifier', 'alt'); - + if (multiCursorModifier === 'ctrlCmd') { // When multiCursorModifier is ctrlCmd, links use Alt/Option return process.platform === 'darwin' ? 'Option' : 'Alt'; diff --git a/src/test/terminals/shellIntegration/pythonStartup.test.ts b/src/test/terminals/shellIntegration/pythonStartup.test.ts index 514bbb86d5e0..fad0deaa9ba6 100644 --- a/src/test/terminals/shellIntegration/pythonStartup.test.ts +++ b/src/test/terminals/shellIntegration/pythonStartup.test.ts @@ -50,10 +50,10 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { pythonConfig = TypeMoq.Mock.ofType(); editorConfig = TypeMoq.Mock.ofType(); - + // Set up default behavior for editor config editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'alt'); - + getConfigurationStub.callsFake((section: string) => { if (section === 'python') { return pythonConfig.object; @@ -212,7 +212,7 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { // Mock the editor configuration to return ctrlCmd editorConfig.reset(); editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd'); - + const provider = new CustomTerminalLinkProvider(); const context: TerminalLinkContext = { line: 'Some random string with Option click to launch VS Code Native REPL', @@ -321,7 +321,7 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { // Mock the editor configuration to return ctrlCmd editorConfig.reset(); editorConfig.setup((p) => p.get('multiCursorModifier', 'alt')).returns(() => 'ctrlCmd'); - + const provider = new CustomTerminalLinkProvider(); const context: TerminalLinkContext = { line: 'Some random string with Alt click to launch VS Code Native REPL', @@ -387,7 +387,7 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { test('Verify provideTerminalLinks adapts to configuration changes', () => { const provider = new CustomTerminalLinkProvider(); - + // Test with default setting (alt) const context1: TerminalLinkContext = { line: 'Some random string with Ctrl click to launch VS Code Native REPL',