Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1626,13 +1626,13 @@
"vscode-languageserver": "^3.1.0",
"winreg": "^1.2.4",
"xml2js": "^0.4.17",
"vscode": "^1.0.3"
"vscode": "^1.1.5"
},
"devDependencies": {
"@types/fs-extra": "^4.0.2",
"@types/jquery": "^1.10.31",
"@types/lodash": "^4.14.74",
"@types/mocha": "^2.2.32",
"@types/mocha": "^2.2.43",
"@types/node": "^6.0.40",
"@types/rx": "^2.5.33",
"@types/semver": "^5.4.0",
Expand Down Expand Up @@ -1660,7 +1660,6 @@
"tslint-microsoft-contrib": "^5.0.1",
"typescript": "^2.5.2",
"typescript-formatter": "^6.0.0",
"vscode": "^1.1.5",
"webpack": "^1.13.2"
}
}
15 changes: 15 additions & 0 deletions src/client/common/contextKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { commands } from 'vscode';

export class ContextKey {
private lastValue: boolean;

constructor(private name: string) { }

public async set(value: boolean): Promise<void> {
if (this.lastValue === value) {
return;
}
this.lastValue = value;
await commands.executeCommand('setContext', this.name, this.lastValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is setContext an Electron/Chrome thing?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vscode thingy

}
}
51 changes: 32 additions & 19 deletions src/client/common/installer.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { error } from './logger';
import * as vscode from 'vscode';
import * as settings from './configSettings';
import * as os from 'os';
import * as vscode from 'vscode';
import { commands, ConfigurationTarget, Disposable, OutputChannel, Terminal, Uri, window, workspace } from 'vscode';
import * as settings from './configSettings';
import { isNotInstalledError } from './helpers';
import { error } from './logger';
import { execPythonFile, getFullyQualifiedPythonInterpreterPath } from './utils';

export enum Product {
pytest,
nosetest,
pylint,
flake8,
pep8,
pylama,
prospector,
pydocstyle,
yapf,
autopep8,
mypy,
unittest,
ctags,
rope
pytest = 1,
nosetest = 2,
pylint = 3,
flake8 = 4,
pep8 = 5,
pylama = 6,
prospector = 7,
pydocstyle = 8,
yapf = 9,
autopep8 = 10,
mypy = 11,
unittest = 12,
ctags = 13,
rope = 14
}

// tslint:disable-next-line:variable-name
const ProductInstallScripts = new Map<Product, string[]>();
ProductInstallScripts.set(Product.autopep8, ['-m', 'pip', 'install', 'autopep8']);
ProductInstallScripts.set(Product.flake8, ['-m', 'pip', 'install', 'flake8']);
Expand All @@ -37,6 +38,7 @@ ProductInstallScripts.set(Product.pytest, ['-m', 'pip', 'install', '-U', 'pytest
ProductInstallScripts.set(Product.yapf, ['-m', 'pip', 'install', 'yapf']);
ProductInstallScripts.set(Product.rope, ['-m', 'pip', 'install', 'rope']);

// tslint:disable-next-line:variable-name
const ProductUninstallScripts = new Map<Product, string[]>();
ProductUninstallScripts.set(Product.autopep8, ['-m', 'pip', 'uninstall', 'autopep8', '--yes']);
ProductUninstallScripts.set(Product.flake8, ['-m', 'pip', 'uninstall', 'flake8', '--yes']);
Expand All @@ -51,6 +53,7 @@ ProductUninstallScripts.set(Product.pytest, ['-m', 'pip', 'uninstall', 'pytest',
ProductUninstallScripts.set(Product.yapf, ['-m', 'pip', 'uninstall', 'yapf', '--yes']);
ProductUninstallScripts.set(Product.rope, ['-m', 'pip', 'uninstall', 'rope', '--yes']);

// tslint:disable-next-line:variable-name
export const ProductExecutableAndArgs = new Map<Product, { executable: string, args: string[] }>();
ProductExecutableAndArgs.set(Product.mypy, { executable: 'python', args: ['-m', 'mypy'] });
ProductExecutableAndArgs.set(Product.nosetest, { executable: 'python', args: ['-m', 'nose'] });
Expand All @@ -77,6 +80,7 @@ switch (os.platform()) {
}
}

// tslint:disable-next-line:variable-name
export const Linters: Product[] = [
Product.flake8,
Product.pep8,
Expand All @@ -87,6 +91,7 @@ export const Linters: Product[] = [
Product.pydocstyle
];

// tslint:disable-next-line:variable-name
const ProductNames = new Map<Product, string>();
ProductNames.set(Product.autopep8, 'autopep8');
ProductNames.set(Product.flake8, 'flake8');
Expand All @@ -101,6 +106,7 @@ ProductNames.set(Product.pytest, 'py.test');
ProductNames.set(Product.yapf, 'yapf');
ProductNames.set(Product.rope, 'rope');

// tslint:disable-next-line:variable-name
export const SettingToDisableProduct = new Map<Product, string>();
SettingToDisableProduct.set(Product.flake8, 'linting.flake8Enabled');
SettingToDisableProduct.set(Product.mypy, 'linting.mypyEnabled');
Expand All @@ -112,6 +118,7 @@ SettingToDisableProduct.set(Product.pydocstyle, 'linting.pydocstyleEnabled');
SettingToDisableProduct.set(Product.pylint, 'linting.pylintEnabled');
SettingToDisableProduct.set(Product.pytest, 'unitTest.pyTestEnabled');

// tslint:disable-next-line:variable-name
const ProductInstallationPrompt = new Map<Product, string>();
ProductInstallationPrompt.set(Product.ctags, 'Install CTags to enable Python workspace symbols');

Expand All @@ -123,13 +130,15 @@ enum ProductType {
WorkspaceSymbols
}

// tslint:disable-next-line:variable-name
const ProductTypeNames = new Map<ProductType, string>();
ProductTypeNames.set(ProductType.Formatter, 'Formatter');
ProductTypeNames.set(ProductType.Linter, 'Linter');
ProductTypeNames.set(ProductType.RefactoringLibrary, 'Refactoring library');
ProductTypeNames.set(ProductType.TestFramework, 'Test Framework');
ProductTypeNames.set(ProductType.WorkspaceSymbols, 'Workspace Symbols');

// tslint:disable-next-line:variable-name
const ProductTypes = new Map<Product, ProductType>();
ProductTypes.set(Product.flake8, ProductType.Linter);
ProductTypes.set(Product.mypy, ProductType.Linter);
Expand Down Expand Up @@ -165,23 +174,26 @@ export class Installer implements vscode.Disposable {
this.disposables.forEach(d => d.dispose());
}
private shouldDisplayPrompt(product: Product) {
// tslint:disable-next-line:no-non-null-assertion
const productName = ProductNames.get(product)!;
const pythonConfig = workspace.getConfiguration('python');
const disablePromptForFeatures = pythonConfig.get('disablePromptForFeatures', [] as string[]);
return disablePromptForFeatures.indexOf(productName) === -1;
}

// tslint:disable-next-line:member-ordering
public async promptToInstall(product: Product, resource?: Uri): Promise<InstallerResponse> {
// tslint:disable-next-line:no-non-null-assertion
const productType = ProductTypes.get(product)!;
const productTypeName = ProductTypeNames.get(productType);
// tslint:disable-next-line:no-non-null-assertion
const productName = ProductNames.get(product)!;

if (!this.shouldDisplayPrompt(product)) {
const message = `${productTypeName} '${productName}' not installed.`;
if (this.outputChannel) {
this.outputChannel.appendLine(message);
}
else {
} else {
console.warn(message);
}
return InstallerResponse.Ignore;
Expand Down Expand Up @@ -229,6 +241,7 @@ export class Installer implements vscode.Disposable {
}
}
}
// tslint:disable-next-line:member-ordering
public async install(product: Product, resource?: Uri): Promise<InstallerResponse> {
if (!this.outputChannel && !Installer.terminal) {
Installer.terminal = window.createTerminal('Python Installer');
Expand Down
103 changes: 32 additions & 71 deletions src/client/extension.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
'use strict';

import * as fs from 'fs';
import * as os from 'os';
import { workspace } from 'vscode';
import * as vscode from 'vscode';
import { JediFactory } from './languageServices/jediProxyFactory';
import * as settings from './common/configSettings';
import { Commands } from './common/constants';
import { createDeferred } from './common/helpers';
import * as telemetryHelper from './common/telemetry';
import * as telemetryContracts from './common/telemetryContracts';
import { SimpleConfigurationProvider } from './debugger';
import { HelpProvider } from './helpProvider';
import { InterpreterManager } from './interpreter';
import { SetInterpreterProvider } from './interpreter/configuration/setInterpreterProvider';
import { ShebangCodeLensProvider } from './interpreter/display/shebangCodeLensProvider';
import * as jup from './jupyter/main';
import { JupyterProvider } from './jupyter/provider';
import { JediFactory } from './languageServices/jediProxyFactory';
import { PythonCompletionItemProvider } from './providers/completionProvider';
import { PythonHoverProvider } from './providers/hoverProvider';
import { PythonDefinitionProvider } from './providers/definitionProvider';
import { PythonReferenceProvider } from './providers/referenceProvider';
import { PythonRenameProvider } from './providers/renameProvider';
import { activateExecInTerminalProvider } from './providers/execInTerminalProvider';
import { activateFormatOnSaveProvider } from './providers/formatOnSaveProvider';
import { PythonFormattingEditProvider } from './providers/formatProvider';
import { ShebangCodeLensProvider } from './providers/shebangCodeLensProvider'
import * as sortImports from './sortImports';
import { PythonHoverProvider } from './providers/hoverProvider';
import { LintProvider } from './providers/lintProvider';
import { PythonSymbolProvider } from './providers/symbolProvider';
import { activateGoToObjectDefinitionProvider } from './providers/objectDefinitionProvider';
import { PythonReferenceProvider } from './providers/referenceProvider';
import { PythonRenameProvider } from './providers/renameProvider';
import { ReplProvider } from './providers/replProvider';
import { PythonSignatureProvider } from './providers/signatureProvider';
import * as settings from './common/configSettings';
import * as telemetryHelper from './common/telemetry';
import * as telemetryContracts from './common/telemetryContracts';
import { activateSimplePythonRefactorProvider } from './providers/simpleRefactorProvider';
import { SetInterpreterProvider } from './providers/setInterpreterProvider';
import { activateExecInTerminalProvider } from './providers/execInTerminalProvider';
import { Commands } from './common/constants';
import * as tests from './unittests/main';
import * as jup from './jupyter/main';
import { HelpProvider } from './helpProvider';
import { PythonSymbolProvider } from './providers/symbolProvider';
import { activateUpdateSparkLibraryProvider } from './providers/updateSparkLibraryProvider';
import { activateFormatOnSaveProvider } from './providers/formatOnSaveProvider';
import { WorkspaceSymbols } from './workspaceSymbols/main';
import * as sortImports from './sortImports';
import { BlockFormatProviders } from './typeFormatters/blockFormatProvider';
import * as os from 'os';
import * as fs from 'fs';
import { JupyterProvider } from './jupyter/provider';
import { activateGoToObjectDefinitionProvider } from './providers/objectDefinitionProvider';
import { InterpreterManager } from './interpreter';
import { SimpleConfigurationProvider } from './debugger';
import { ReplProvider } from './providers/replProvider';
import { workspace } from 'vscode';
import * as tests from './unittests/main';
import { WorkspaceSymbols } from './workspaceSymbols/main';

const PYTHON: vscode.DocumentFilter = { language: 'python' };
let unitTestOutChannel: vscode.OutputChannel;
Expand All @@ -44,10 +44,9 @@ let lintingOutChannel: vscode.OutputChannel;
let jupMain: jup.Jupyter;
const activationDeferred = createDeferred<void>();
export const activated = activationDeferred.promise;
// tslint:disable-next-line:max-func-body-length
export async function activate(context: vscode.ExtensionContext) {
const pythonSettings = settings.PythonSettings.getInstance();
const pythonExt = new PythonExt();
context.subscriptions.push(pythonExt);
sendStartupTelemetry();
lintingOutChannel = vscode.window.createOutputChannel(pythonSettings.linting.outputWindow);
formatOutChannel = lintingOutChannel;
Expand Down Expand Up @@ -85,11 +84,11 @@ export async function activate(context: vscode.ExtensionContext) {
{
beforeText: /^ *#.*$/,
afterText: /.+$/,
action: { indentAction: vscode.IndentAction.None, appendText: '# ' },
action: { indentAction: vscode.IndentAction.None, appendText: '# ' }
},
{
beforeText: /^\s+(continue|break|return)\b.*$/,
action: { indentAction: vscode.IndentAction.Outdent },
action: { indentAction: vscode.IndentAction.Outdent }
}
]
});
Expand All @@ -101,7 +100,7 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.languages.registerHoverProvider(PYTHON, new PythonHoverProvider(jediFactory)));
context.subscriptions.push(vscode.languages.registerReferenceProvider(PYTHON, new PythonReferenceProvider(jediFactory)));
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(PYTHON, new PythonCompletionItemProvider(jediFactory), '.'));
context.subscriptions.push(vscode.languages.registerCodeLensProvider(PYTHON, new ShebangCodeLensProvider()))
context.subscriptions.push(vscode.languages.registerCodeLensProvider(PYTHON, new ShebangCodeLensProvider()));

const symbolProvider = new PythonSymbolProvider(jediFactory);
context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(PYTHON, symbolProvider));
Expand All @@ -115,7 +114,7 @@ export async function activate(context: vscode.ExtensionContext) {
}

const jupyterExtInstalled = vscode.extensions.getExtension('donjayamanne.jupyter');
let linterProvider = new LintProvider(context, lintingOutChannel, (a, b) => Promise.resolve(false));
const linterProvider = new LintProvider(context, lintingOutChannel, (a, b) => Promise.resolve(false));
context.subscriptions.push();
if (jupyterExtInstalled) {
if (jupyterExtInstalled.isActive) {
Expand All @@ -127,8 +126,7 @@ export async function activate(context: vscode.ExtensionContext) {
jupyterExtInstalled.exports.registerLanguageProvider(PYTHON.language, new JupyterProvider());
linterProvider.documentHasJupyterCodeCells = jupyterExtInstalled.exports.hasCodeCells;
});
}
else {
} else {
jupMain = new jup.Jupyter(lintingOutChannel);
const documentHasJupyterCodeCells = jupMain.hasCodeCells.bind(jupMain);
jupMain.activate();
Expand All @@ -151,43 +149,6 @@ export async function activate(context: vscode.ExtensionContext) {
activationDeferred.resolve();
}

class PythonExt implements vscode.Disposable {

private isDjangoProject: ContextKey;

constructor() {
this.isDjangoProject = new ContextKey('python.isDjangoProject');
this.ensureState();
}
public dispose() {
this.isDjangoProject = null;
}
private ensureState(): void {
// context: python.isDjangoProject
if (typeof vscode.workspace.rootPath === 'string') {
this.isDjangoProject.set(fs.existsSync(vscode.workspace.rootPath.concat("/manage.py")));
}
else {
this.isDjangoProject.set(false);
}
}
}

class ContextKey {
private lastValue: boolean;

constructor(private name: string) {
}

public set(value: boolean): void {
if (this.lastValue === value) {
return;
}
this.lastValue = value;
vscode.commands.executeCommand('setContext', this.name, this.lastValue);
}
}

function sendStartupTelemetry() {
telemetryHelper.sendTelemetryEvent(telemetryContracts.EVENT_LOAD);
}
41 changes: 41 additions & 0 deletions src/client/interpreter/configuration/pythonPathUpdaterService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as path from 'path';
import { ConfigurationTarget, Uri, window } from 'vscode';
import { WorkspacePythonPath } from '../contracts';
import { IPythonPathUpdaterService, IPythonPathUpdaterServiceFactory } from './types';

export class PythonPathUpdaterService {
constructor(private pythonPathSettingsUpdaterFactory: IPythonPathUpdaterServiceFactory) { }
public async updatePythonPath(pythonPath: string, configTarget: ConfigurationTarget, wkspace?: Uri): Promise<void> {
const pythonPathUpdater = this.getPythonUpdaterService(configTarget, wkspace);

try {
await pythonPathUpdater.updatePythonPath(path.normalize(pythonPath));
} catch (reason) {
// tslint:disable-next-line:no-unsafe-any prefer-type-cast
const message = reason && typeof reason.message === 'string' ? reason.message as string : '';
window.showErrorMessage(`Failed to set 'pythonPath'. Error: ${message}`);
console.error(reason);
}
}
private getPythonUpdaterService(configTarget: ConfigurationTarget, wkspace?: Uri) {
switch (configTarget) {
case ConfigurationTarget.Global: {
return this.pythonPathSettingsUpdaterFactory.getGlobalPythonPathConfigurationService();
}
case ConfigurationTarget.Workspace: {
if (!wkspace) {
throw new Error('Workspace Uri not defined');
}
// tslint:disable-next-line:no-non-null-assertion
return this.pythonPathSettingsUpdaterFactory.getWorkspacePythonPathConfigurationService(wkspace!);
}
default: {
if (!wkspace) {
throw new Error('Workspace Uri not defined');
}
// tslint:disable-next-line:no-non-null-assertion
return this.pythonPathSettingsUpdaterFactory.getWorkspaceFolderPythonPathConfigurationService(wkspace!);
}
}
}
}
Loading