diff --git a/news/2 Fixes/11687.md b/news/2 Fixes/11687.md new file mode 100644 index 000000000000..d34a4a5bccfc --- /dev/null +++ b/news/2 Fixes/11687.md @@ -0,0 +1 @@ +Do not execute shebang as an interpreter until user has clicked on the codelens enclosing the shebang. diff --git a/src/client/interpreter/configuration/interpreterSelector/commands/setShebangInterpreter.ts b/src/client/interpreter/configuration/interpreterSelector/commands/setShebangInterpreter.ts index 82834395f976..e3e63b299f83 100644 --- a/src/client/interpreter/configuration/interpreterSelector/commands/setShebangInterpreter.ts +++ b/src/client/interpreter/configuration/interpreterSelector/commands/setShebangInterpreter.ts @@ -37,7 +37,8 @@ export class SetShebangInterpreterCommand extends BaseInterpreterSelectorCommand protected async setShebangInterpreter(): Promise { const shebang = await this.shebangCodeLensProvider.detectShebang( - this.documentManager.activeTextEditor!.document + this.documentManager.activeTextEditor!.document, + true ); if (!shebang) { return; diff --git a/src/client/interpreter/contracts.ts b/src/client/interpreter/contracts.ts index 6013ff504bd2..55b203667ab7 100644 --- a/src/client/interpreter/contracts.ts +++ b/src/client/interpreter/contracts.ts @@ -114,7 +114,7 @@ export interface IInterpreterDisplay { export const IShebangCodeLensProvider = Symbol('IShebangCodeLensProvider'); export interface IShebangCodeLensProvider extends CodeLensProvider { - detectShebang(document: TextDocument): Promise; + detectShebang(document: TextDocument, resolveShebangAsInterpreter?: boolean): Promise; } export const IInterpreterHelper = Symbol('IInterpreterHelper'); diff --git a/src/client/interpreter/display/shebangCodeLensProvider.ts b/src/client/interpreter/display/shebangCodeLensProvider.ts index f545abe86de9..8737981c8369 100644 --- a/src/client/interpreter/display/shebangCodeLensProvider.ts +++ b/src/client/interpreter/display/shebangCodeLensProvider.ts @@ -19,7 +19,10 @@ export class ShebangCodeLensProvider implements IShebangCodeLensProvider { // tslint:disable-next-line:no-any this.onDidChangeCodeLenses = (workspaceService.onDidChangeConfiguration as any) as Event; } - public async detectShebang(document: TextDocument): Promise { + public async detectShebang( + document: TextDocument, + resolveShebangAsInterpreter: boolean = false + ): Promise { const firstLine = document.lineAt(0); if (firstLine.isEmptyOrWhitespace) { return; @@ -30,8 +33,12 @@ export class ShebangCodeLensProvider implements IShebangCodeLensProvider { } const shebang = firstLine.text.substr(2).trim(); - const pythonPath = await this.getFullyQualifiedPathToInterpreter(shebang, document.uri); - return typeof pythonPath === 'string' && pythonPath.length > 0 ? pythonPath : undefined; + if (resolveShebangAsInterpreter) { + const pythonPath = await this.getFullyQualifiedPathToInterpreter(shebang, document.uri); + return typeof pythonPath === 'string' && pythonPath.length > 0 ? pythonPath : undefined; + } else { + return typeof shebang === 'string' && shebang.length > 0 ? shebang : undefined; + } } public async provideCodeLenses(document: TextDocument, _token?: CancellationToken): Promise { return this.createShebangCodeLens(document); diff --git a/src/test/providers/shebangCodeLenseProvider.unit.test.ts b/src/test/providers/shebangCodeLenseProvider.unit.test.ts index 76edd0facae4..c878cb34a9fa 100644 --- a/src/test/providers/shebangCodeLenseProvider.unit.test.ts +++ b/src/test/providers/shebangCodeLenseProvider.unit.test.ts @@ -63,15 +63,33 @@ suite('Shebang detection', () => { return [doc, line]; } - test('Shebang should be empty when first line is empty', async () => { + test('Shebang should be empty when first line is empty when resolving shebang as interpreter', async () => { const [document, line] = createDocument(''); - const shebang = await provider.detectShebang(document.object); + const shebang = await provider.detectShebang(document.object, true); document.verifyAll(); line.verifyAll(); expect(shebang).to.be.equal(undefined, 'Shebang should be undefined'); }); + test('Shebang should be empty when first line is empty when not resolving shebang as interpreter', async () => { + const [document, line] = createDocument(''); + + const shebang = await provider.detectShebang(document.object, false); + + document.verifyAll(); + line.verifyAll(); + expect(shebang).to.be.equal(undefined, 'Shebang should be undefined'); + }); + test('Shebang should be returned as it is when not resolving shebang as interpreter', async () => { + const [document, line] = createDocument('#!HELLO'); + + const shebang = await provider.detectShebang(document.object, false); + + document.verifyAll(); + line.verifyAll(); + expect(shebang).to.be.equal('HELLO', 'Shebang should be HELLO'); + }); test('Shebang should be empty when python path is invalid in shebang', async () => { const [document, line] = createDocument('#!HELLO'); @@ -80,7 +98,7 @@ suite('Shebang detection', () => { .returns(() => Promise.reject()) .verifiable(typemoq.Times.once()); - const shebang = await provider.detectShebang(document.object); + const shebang = await provider.detectShebang(document.object, true); document.verifyAll(); line.verifyAll(); @@ -95,7 +113,7 @@ suite('Shebang detection', () => { .returns(() => Promise.resolve({ stdout: 'THIS_IS_IT' })) .verifiable(typemoq.Times.once()); - const shebang = await provider.detectShebang(document.object); + const shebang = await provider.detectShebang(document.object, true); document.verifyAll(); line.verifyAll(); @@ -113,7 +131,7 @@ suite('Shebang detection', () => { .returns(() => Promise.resolve({ stdout: 'THIS_IS_IT' })) .verifiable(typemoq.Times.once()); - const shebang = await provider.detectShebang(document.object); + const shebang = await provider.detectShebang(document.object, true); document.verifyAll(); line.verifyAll(); @@ -132,7 +150,7 @@ suite('Shebang detection', () => { .returns(() => Promise.resolve({ stdout: 'THIS_IS_IT' })) .verifiable(typemoq.Times.once()); - const shebang = await provider.detectShebang(document.object); + const shebang = await provider.detectShebang(document.object, true); document.verifyAll(); line.verifyAll();