1- 'use strict' ;
2- import * as child_process from 'child_process' ;
31import * as vscode from 'vscode' ;
42import { CancellationToken , CodeLens , TextDocument } from 'vscode' ;
53import * as settings from '../../common/configSettings' ;
4+ import { IProcessService } from '../../common/process/types' ;
65import { IS_WINDOWS } from '../../common/utils' ;
7- import { getFirstNonEmptyLineFromMultilineString } from '../../interpreter/helpers' ;
86
97export class ShebangCodeLensProvider implements vscode . CodeLensProvider {
10- // tslint:disable-next-line:prefer-type-cast no-any
8+ // tslint:disable-next-line:no-any
119 public onDidChangeCodeLenses : vscode . Event < void > = vscode . workspace . onDidChangeConfiguration as any as vscode . Event < void > ;
12- // tslint:disable-next-line:function-name
13- public static async detectShebang ( document : TextDocument ) : Promise < string | undefined > {
10+ constructor ( private processService : IProcessService ) { }
11+ public async detectShebang ( document : TextDocument ) : Promise < string | undefined > {
1412 const firstLine = document . lineAt ( 0 ) ;
1513 if ( firstLine . isEmptyOrWhitespace ) {
1614 return ;
@@ -21,40 +19,30 @@ export class ShebangCodeLensProvider implements vscode.CodeLensProvider {
2119 }
2220
2321 const shebang = firstLine . text . substr ( 2 ) . trim ( ) ;
24- const pythonPath = await ShebangCodeLensProvider . getFullyQualifiedPathToInterpreter ( shebang ) ;
22+ const pythonPath = await this . getFullyQualifiedPathToInterpreter ( shebang ) ;
2523 return typeof pythonPath === 'string' && pythonPath . length > 0 ? pythonPath : undefined ;
2624 }
27- private static async getFullyQualifiedPathToInterpreter ( pythonPath : string ) {
28- if ( pythonPath . indexOf ( 'bin/env ' ) >= 0 && ! IS_WINDOWS ) {
29- // In case we have pythonPath as '/usr/bin/env python'
30- return new Promise < string > ( resolve => {
31- const command = child_process . exec ( `${ pythonPath } -c 'import sys;print(sys.executable)'` ) ;
32- let result = '' ;
33- command . stdout . on ( 'data' , ( data ) => {
34- result += data . toString ( ) ;
35- } ) ;
36- command . on ( 'close' , ( ) => {
37- resolve ( getFirstNonEmptyLineFromMultilineString ( result ) ) ;
38- } ) ;
39- } ) ;
40- } else {
41- return new Promise < string > ( resolve => {
42- child_process . execFile ( pythonPath , [ '-c' , 'import sys;print(sys.executable)' ] , ( _ , stdout ) => {
43- resolve ( getFirstNonEmptyLineFromMultilineString ( stdout ) ) ;
44- } ) ;
45- } ) ;
46- }
47- }
48-
4925 public async provideCodeLenses ( document : TextDocument , token : CancellationToken ) : Promise < CodeLens [ ] > {
5026 const codeLenses = await this . createShebangCodeLens ( document ) ;
5127 return Promise . resolve ( codeLenses ) ;
5228 }
53-
29+ private async getFullyQualifiedPathToInterpreter ( pythonPath : string ) {
30+ let cmdFile = pythonPath ;
31+ let args = [ '-c' , 'import sys;print(sys.executable)' ] ;
32+ if ( pythonPath . indexOf ( 'bin/env ' ) >= 0 && ! IS_WINDOWS ) {
33+ // In case we have pythonPath as '/usr/bin/env python'.
34+ const parts = pythonPath . split ( ' ' ) . map ( part => part . trim ( ) ) . filter ( part => part . length > 0 ) ;
35+ cmdFile = parts . shift ( ) ! ;
36+ args = parts . concat ( args ) ;
37+ }
38+ return this . processService . exec ( cmdFile , args )
39+ . then ( output => output . stdout . trim ( ) )
40+ . catch ( ( ) => '' ) ;
41+ }
5442 private async createShebangCodeLens ( document : TextDocument ) {
55- const shebang = await ShebangCodeLensProvider . detectShebang ( document ) ;
43+ const shebang = await this . detectShebang ( document ) ;
5644 const pythonPath = settings . PythonSettings . getInstance ( document . uri ) . pythonPath ;
57- const resolvedPythonPath = await ShebangCodeLensProvider . getFullyQualifiedPathToInterpreter ( pythonPath ) ;
45+ const resolvedPythonPath = await this . getFullyQualifiedPathToInterpreter ( pythonPath ) ;
5846 if ( ! shebang || shebang === resolvedPythonPath ) {
5947 return [ ] ;
6048 }
0 commit comments