Skip to content

Commit

Permalink
Ensure interpreter is auto selected before updating status bar (#4139)
Browse files Browse the repository at this point in the history
For #3501
  • Loading branch information
DonJayamanne committed Jan 25, 2019
1 parent 6ed1f95 commit 6774512
Show file tree
Hide file tree
Showing 35 changed files with 547 additions and 259 deletions.
62 changes: 31 additions & 31 deletions src/client/activation/activationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { inject, injectable, multiInject } from 'inversify';
import { TextDocument, workspace } from 'vscode';
import { IApplicationDiagnostics } from '../application/types';
import { IDocumentManager, IWorkspaceService } from '../common/application/types';
import { isTestExecution } from '../common/constants';
import { PYTHON_LANGUAGE } from '../common/constants';
import { traceDecorators } from '../common/logger';
import { IDisposable, Resource } from '../common/types';
import { IInterpreterAutoSelectionService } from '../interpreter/autoSelection/types';
Expand All @@ -26,27 +26,40 @@ export class ExtensionActivationManager implements IExtensionActivationManager {
@inject(IInterpreterAutoSelectionService) private readonly autoSelection: IInterpreterAutoSelectionService,
@inject(IApplicationDiagnostics) private readonly appDiagnostics: IApplicationDiagnostics,
@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService
) { }
) {}

public dispose() {
while (this.disposables.length > 0) {
const disposable = this.disposables.shift();
const disposable = this.disposables.shift()!;
disposable.dispose();
}
if (this. docOpenedHandler){
if (this.docOpenedHandler) {
this.docOpenedHandler.dispose();
this.docOpenedHandler = undefined;
}
}
public async activate(): Promise<void> {
await this.initialize();
await this.activateWorkspace(this.getActiveResource());
await this.autoSelection.autoSelectInterpreter(undefined);
}
@traceDecorators.error('Failed to activate a workspace')
public async activateWorkspace(resource: Resource) {
const key = this.getWorkspaceKey(resource);
if (this.activatedWorkspaces.has(key)) {
return;
}
this.activatedWorkspaces.add(key);
// Get latest interpreter list in the background.
this.interpreterService.getInterpreters(resource).ignoreErrors();

await this.autoSelection.autoSelectInterpreter(resource);
await Promise.all(this.activationServices.map(item => item.activate(resource)));
await this.appDiagnostics.performPreStartupHealthCheck(resource);
}
protected async initialize() {
// Get latest interpreter list.
const mainWorkspaceUri = this.getActiveResource();
this.interpreterService.getInterpreters(mainWorkspaceUri).ignoreErrors();
this.addHandlers();
this.addRemoveDocOpenedHandlers();
}
protected addHandlers() {
this.disposables.push(this.workspaceService.onDidChangeWorkspaceFolders(this.onWorkspaceFoldersChanged, this));
Expand All @@ -67,45 +80,32 @@ export class ExtensionActivationManager implements IExtensionActivationManager {
this.addRemoveDocOpenedHandlers();
}
protected hasMultipleWorkspaces() {
return this.workspaceService.hasWorkspaceFolders && this.workspaceService.workspaceFolders.length > 1;
return this.workspaceService.hasWorkspaceFolders && this.workspaceService.workspaceFolders!.length > 1;
}
protected onDocOpened(doc: TextDocument) {
if (doc.languageId !== PYTHON_LANGUAGE) {
return;
}
const key = this.getWorkspaceKey(doc.uri);
// If we have opened a doc that does not belong to workspace, then do nothing.
if (key === '' && this.workspaceService.hasWorkspaceFolders) {
return;
}
if (this.activatedWorkspaces.has(key)) {
return;
}
const folder = this.workspaceService.getWorkspaceFolder(doc.uri);
this.activateWorkspace(folder ? folder.uri : undefined).ignoreErrors();
}
@traceDecorators.error('Failed to activate a worksapce')
protected async activateWorkspace(resource: Resource) {
const key = this.getWorkspaceKey(resource);
this.activatedWorkspaces.add(key);

await Promise.all(this.activationServices.map(item => item.activate(resource)));

// When testing, do not perform health checks, as modal dialogs can be displayed.
if (!isTestExecution()) {
await this.appDiagnostics.performPreStartupHealthCheck(resource);
}
await this.autoSelection.autoSelectInterpreter(resource);
}
protected getWorkspaceKey(resource: Resource) {
if (!resource) {
return '';
}
const workspaceFolder = this.workspaceService.getWorkspaceFolder(resource);
if (!workspaceFolder) {
return '';
}
return workspaceFolder.uri.fsPath;
return this.workspaceService.getWorkspaceFolderIdentifier(resource, '');
}
private getActiveResource(): Resource {
if (this.documentManager.activeTextEditor && !this.documentManager.activeTextEditor.document.isUntitled) {
return this.documentManager.activeTextEditor.document.uri;
}
return Array.isArray(this.workspaceService.workspaceFolders) && workspace.workspaceFolders.length > 0
? workspace.workspaceFolders[0].uri
return Array.isArray(this.workspaceService.workspaceFolders) && workspace.workspaceFolders!.length > 0
? workspace.workspaceFolders![0].uri
: undefined;
}
}
13 changes: 6 additions & 7 deletions src/client/activation/activationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ type ActivatorInfo = { jedi: boolean; activator: ILanguageServerActivator };
@injectable()
export class LanguageServerExtensionActivationService implements IExtensionActivationService, Disposable {
private currentActivator?: ActivatorInfo;
private activatedOnce: boolean;
private activatedOnce: boolean = false;
private readonly workspaceService: IWorkspaceService;
private readonly output: OutputChannel;
private readonly appShell: IApplicationShell;
private readonly lsNotSupportedDiagnosticService: IDiagnosticsService;
private resource!: Resource;

constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
this.workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
Expand All @@ -41,10 +42,11 @@ export class LanguageServerExtensionActivationService implements IExtensionActiv
disposables.push(this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)));
}

public async activate(_resource: Resource): Promise<void> {
public async activate(resource: Resource): Promise<void> {
if (this.currentActivator || this.activatedOnce) {
return;
}
this.resource = resource;
this.activatedOnce = true;

let jedi = this.useJedi();
Expand Down Expand Up @@ -114,10 +116,7 @@ export class LanguageServerExtensionActivationService implements IExtensionActiv
}
}
private useJedi(): boolean {
const workspacesUris: (Uri | undefined)[] = this.workspaceService.hasWorkspaceFolders
? this.workspaceService.workspaceFolders!.map(item => item.uri)
: [undefined];
const configuraionService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
return workspacesUris.filter(uri => configuraionService.getSettings(uri).jediEnabled).length > 0;
const configurationService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
return configurationService.getSettings(this.resource).jediEnabled;
}
}
1 change: 1 addition & 0 deletions src/client/activation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { IDisposable, LanguageServerDownloadChannels, Resource } from '../common
export const IExtensionActivationManager = Symbol('IExtensionActivationManager');
export interface IExtensionActivationManager extends IDisposable {
activate(): Promise<void>;
activateWorkspace(resource: Resource): Promise<void>;
}

export const IExtensionActivationService = Symbol('IExtensionActivationService');
Expand Down
6 changes: 5 additions & 1 deletion src/client/application/diagnostics/applicationDiagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { inject, injectable, named } from 'inversify';
import { DiagnosticSeverity } from 'vscode';
import { STANDARD_OUTPUT_CHANNEL } from '../../common/constants';
import { isTestExecution, STANDARD_OUTPUT_CHANNEL } from '../../common/constants';
import { ILogger, IOutputChannel, Resource } from '../../common/types';
import { IServiceContainer } from '../../ioc/types';
import { IApplicationDiagnostics } from '../types';
Expand All @@ -21,6 +21,10 @@ export class ApplicationDiagnostics implements IApplicationDiagnostics {
this.serviceContainer.get<ISourceMapSupportService>(ISourceMapSupportService).register();
}
public async performPreStartupHealthCheck(resource: Resource): Promise<void> {
// When testing, do not perform health checks, as modal dialogs can be displayed.
if (!isTestExecution()) {
return;
}
const services = this.serviceContainer.getAll<IDiagnosticsService>(IDiagnosticsService);
// Perform these validation checks in the foreground.
await this.runDiagnostics(services.filter(item => !item.runInBackground), resource);
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ export interface IWorkspaceService {
* @returns {string}
* @memberof IWorkspaceService
*/
getWorkspaceFolderIdentifier(resource: Uri | undefined): string;
getWorkspaceFolderIdentifier(resource: Uri | undefined, defaultValue?: string): string;
/**
* Returns a path that is relative to the workspace folder or folders.
*
Expand Down
5 changes: 3 additions & 2 deletions src/client/common/application/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { injectable } from 'inversify';
import { CancellationToken, ConfigurationChangeEvent, Event, FileSystemWatcher, GlobPattern, Uri, workspace, WorkspaceConfiguration, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode';
import { Resource } from '../types';
import { IWorkspaceService } from './types';

@injectable()
Expand Down Expand Up @@ -37,8 +38,8 @@ export class WorkspaceService implements IWorkspaceService {
public findFiles(include: GlobPattern, exclude?: GlobPattern, maxResults?: number, token?: CancellationToken): Thenable<Uri[]> {
return workspace.findFiles(include, exclude, maxResults, token);
}
public getWorkspaceFolderIdentifier(resource: Uri): string {
public getWorkspaceFolderIdentifier(resource: Resource, defaultValue: string = ''): string {
const workspaceFolder = resource ? workspace.getWorkspaceFolder(resource) : undefined;
return workspaceFolder ? workspaceFolder.uri.fsPath : '';
return workspaceFolder ? workspaceFolder.uri.fsPath : defaultValue;
}
}
8 changes: 4 additions & 4 deletions src/client/common/configSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class PythonSettings implements IPythonSettings {
return this.changed.event;
}

constructor(workspaceFolder: Uri | undefined, private readonly InterpreterAutoSelectionService: IInterpreterAutoSeletionProxyService,
constructor(workspaceFolder: Uri | undefined, private readonly interpreterAutoSelectionService: IInterpreterAutoSeletionProxyService,
workspace?: IWorkspaceService) {
this.workspace = workspace || new WorkspaceService();
this.workspaceRoot = workspaceFolder ? workspaceFolder : Uri.file(__dirname);
Expand Down Expand Up @@ -129,9 +129,9 @@ export class PythonSettings implements IPythonSettings {
this.pythonPath = systemVariables.resolveAny(pythonSettings.get<string>('pythonPath'))!;
// If user has defined a custom value, use it else try to get the best interpreter ourselves.
if (this.pythonPath.length === 0 || this.pythonPath === 'python') {
const autoSelectedPythonInterpreter = this.InterpreterAutoSelectionService.getAutoSelectedInterpreter(this.workspaceRoot);
const autoSelectedPythonInterpreter = this.interpreterAutoSelectionService.getAutoSelectedInterpreter(this.workspaceRoot);
if (autoSelectedPythonInterpreter) {
this.InterpreterAutoSelectionService.setWorkspaceInterpreter(this.workspaceRoot, autoSelectedPythonInterpreter).ignoreErrors();
this.interpreterAutoSelectionService.setWorkspaceInterpreter(this.workspaceRoot, autoSelectedPythonInterpreter).ignoreErrors();
}
this.pythonPath = autoSelectedPythonInterpreter ? autoSelectedPythonInterpreter.path : this.pythonPath;
}
Expand Down Expand Up @@ -382,7 +382,7 @@ export class PythonSettings implements IPythonSettings {
// Let's defer the change notification.
this.debounceChangeNotification();
};
this.disposables.push(this.InterpreterAutoSelectionService.onDidChangeAutoSelectedInterpreter(onDidChange.bind(this)));
this.disposables.push(this.interpreterAutoSelectionService.onDidChangeAutoSelectedInterpreter(onDidChange.bind(this)));
this.disposables.push(this.workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
if (event.affectsConfiguration('python')) {
onDidChange();
Expand Down
1 change: 1 addition & 0 deletions src/client/common/process/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export type InterpreterInfomation = {
sysVersion: string;
architecture: Architecture;
sysPrefix: string;
pipEnvWorkspaceFolder?: string;
};
export const IPythonExecutionService = Symbol('IPythonExecutionService');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
import { inject, injectable } from 'inversify';
import { Uri } from 'vscode';
import { IInterpreterService, InterpreterType, IPipEnvService } from '../../../interpreter/contracts';
import { IWorkspaceService } from '../../application/types';
import { IFileSystem } from '../../platform/types';
import { ITerminalActivationCommandProvider, TerminalShellType } from '../types';

@injectable()
export class PipEnvActivationCommandProvider implements ITerminalActivationCommandProvider {
constructor(
@inject(IInterpreterService) private readonly interpreterService: IInterpreterService,
@inject(IPipEnvService) private readonly pipenvService: IPipEnvService
@inject(IPipEnvService) private readonly pipenvService: IPipEnvService,
@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService,
@inject(IFileSystem) private readonly fs: IFileSystem
) { }

public isShellSupported(_targetShell: TerminalShellType): boolean {
Expand All @@ -24,7 +28,12 @@ export class PipEnvActivationCommandProvider implements ITerminalActivationComma
if (!interpreter || interpreter.type !== InterpreterType.Pipenv) {
return;
}

// Activate using `pipenv shell` only if the current folder relates pipenv environment.
const workspaceFolder = resource ? this.workspaceService.getWorkspaceFolder(resource) : undefined;
if (workspaceFolder && interpreter.pipEnvWorkspaceFolder &&
!this.fs.arePathsSame(workspaceFolder.uri.fsPath, interpreter.pipEnvWorkspaceFolder)) {
return;
}
const execName = this.pipenvService.executable;
return [`${execName.fileToCommandArgument()} shell`];
}
Expand Down
Loading

0 comments on commit 6774512

Please sign in to comment.