Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* 'master' of https://github.com/DonJayamanne/pythonVSCode:
  Fix #996 async with EXPR as VAR (#1108)
  fix changelog typo (#1107)
  #764 feature request: auto import (#1032)
  • Loading branch information
DonJayamanne committed Jul 24, 2017
2 parents a2be9e6 + a3dcaca commit 0b4dbcb
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
### Version 0.6.8 (20 July 2017)
* Add new editor menu 'Run Current Unit Test File' [#1061](https://github.com/DonJayamanne/pythonVSCode/issues/1061)
* Changed 'mypy-lang' to mypy [#930](https://github.com/DonJayamanne/pythonVSCode/issues/930), [#998](https://github.com/DonJayamanne/pythonVSCode/issues/998), [#505](https://github.com/DonJayamanne/pythonVSCode/issues/505)
* Using "Python -m" to launch linters [#716](https://github.com/DonJayamanne/pythonVSCode/issues/930), [#9716](https://github.com/DonJayamanne/pythonVSCode/issues/923), [#1059](https://github.com/DonJayamanne/pythonVSCode/issues/1059)
* Using "Python -m" to launch linters [#716](https://github.com/DonJayamanne/pythonVSCode/issues/716), [#923](https://github.com/DonJayamanne/pythonVSCode/issues/923), [#1059](https://github.com/DonJayamanne/pythonVSCode/issues/1059)
* Add PEP 526 AutoCompletion [#1102](https://github.com/DonJayamanne/pythonVSCode/pull/1102), [#1101](https://github.com/DonJayamanne/pythonVSCode/issues/1101)
* Resolved issues in Go To and Peek Definitions [#1085](https://github.com/DonJayamanne/pythonVSCode/pull/1085), [#961](https://github.com/DonJayamanne/pythonVSCode/issues/961), [#870](https://github.com/DonJayamanne/pythonVSCode/issues/870)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ For further information and details continue through to the [documentation](http
### Version 0.6.8 (20 July 2017)
* Add new editor menu 'Run Current Unit Test File' [#1061](https://github.com/DonJayamanne/pythonVSCode/issues/1061)
* Changed 'mypy-lang' to mypy [#930](https://github.com/DonJayamanne/pythonVSCode/issues/930), [#998](https://github.com/DonJayamanne/pythonVSCode/issues/998), [#505](https://github.com/DonJayamanne/pythonVSCode/issues/505)
* Using "Python -m" to launch linters [#716](https://github.com/DonJayamanne/pythonVSCode/issues/930), [#9716](https://github.com/DonJayamanne/pythonVSCode/issues/923), [#1059](https://github.com/DonJayamanne/pythonVSCode/issues/1059)
* Using "Python -m" to launch linters [#716](https://github.com/DonJayamanne/pythonVSCode/issues/716), [#923](https://github.com/DonJayamanne/pythonVSCode/issues/923), [#1059](https://github.com/DonJayamanne/pythonVSCode/issues/1059)
* Add PEP 526 AutoCompletion [#1102](https://github.com/DonJayamanne/pythonVSCode/pull/1102), [#1101](https://github.com/DonJayamanne/pythonVSCode/issues/1101)
* Resolved issues in Go To and Peek Definitions [#1085](https://github.com/DonJayamanne/pythonVSCode/pull/1085), [#961](https://github.com/DonJayamanne/pythonVSCode/issues/961), [#870](https://github.com/DonJayamanne/pythonVSCode/issues/870)

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1506,11 +1506,13 @@
"@types/socket.io": "^1.4.27",
"@types/socket.io-client": "^1.4.27",
"@types/uuid": "^3.3.27",
"@types/sinon": "^2.3.2",
"babel-core": "^6.14.0",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.14.0",
"ignore-loader": "^0.1.1",
"mocha": "^2.3.3",
"sinon": "^2.3.6",
"retyped-diff-match-patch-tsd-ambient": "^1.0.0-0",
"ts-loader": "^0.8.2",
"tslint": "^3.15.1",
Expand Down
2 changes: 1 addition & 1 deletion snippets/python.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
"async/with": {
"prefix": "async/with",
"body": [
"async with ${1:expr} in ${2:var}:",
"async with ${1:expr} as ${2:var}:",
"\t${3:block}"
],
"description": "Code snippet for a async with statement"
Expand Down
12 changes: 12 additions & 0 deletions src/client/autoImport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { AutoImportProvider } from './providers/autoImportProvider';


export function activate(context: vscode.ExtensionContext, outChannel: vscode.OutputChannel) {
let extension = new AutoImportProvider();
context.subscriptions.push(vscode.commands.registerCommand('python.autoImportAtCursor', extension.autoImportAtCursor));
}
2 changes: 2 additions & 0 deletions src/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { PythonReferenceProvider } from './providers/referenceProvider';
import { PythonRenameProvider } from './providers/renameProvider';
import { PythonFormattingEditProvider } from './providers/formatProvider';
import * as sortImports from './sortImports';
import * as autoImport from './autoImport';
import { LintProvider } from './providers/lintProvider';
import { PythonSymbolProvider } from './providers/symbolProvider';
import { PythonSignatureProvider } from './providers/signatureProvider';
Expand Down Expand Up @@ -58,6 +59,7 @@ export function activate(context: vscode.ExtensionContext) {
}

sortImports.activate(context, formatOutChannel);
autoImport.activate(context, formatOutChannel);
context.subscriptions.push(activateSetInterpreterProvider());
context.subscriptions.push(...activateExecInTerminalProvider());
context.subscriptions.push(activateUpdateSparkLibraryProvider());
Expand Down
85 changes: 85 additions & 0 deletions src/client/providers/autoImportProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

export class AutoImportProvider {

constructor() {
}

autoImportAtCursor() {
let ed = vscode.window.activeTextEditor;
let range : vscode.Range = ed.selection;

if(range.start.line !== range.end.line) {
return;
}

if(range.start.character === range.end.character) {
range = ed.document.getWordRangeAtPosition(range.end);
}
const symbol = vscode.window.activeTextEditor.document.getText(range);

if(!symbol) {
return;
}

return this.autoImport(symbol);
}

async autoImport(symbol: string) {
let editor = vscode.window.activeTextEditor;
let result = await this.lookupSymbol(symbol);

result = result.filter((s: vscode.SymbolInformation) =>
s.name === symbol && // Only exact and case sensitive matches should be considered for import
s.kind !== vscode.SymbolKind.Namespace // only declarations should be considered for import
);

if(result.length === 0) {
vscode.window.showInformationMessage('No matching symbols found');
return;
} else {
var import_choices: string[] = result.map(
s => `from ${pathAsPyModule(s.location)} import ${s.name}`
);

let s = await this.showChoices(import_choices);
if(s) {
return addImport(editor, s);
}
}
}

lookupSymbol(symbol: string) {
return <Promise<vscode.SymbolInformation[]>>
vscode.commands.executeCommand('vscode.executeWorkspaceSymbolProvider', symbol);
}

showChoices(import_choices: string[]) {
return vscode.window.showQuickPick(import_choices);
}
}

export function pathAsPyModule(l: vscode.Location): string {
var pymodule = path.basename(l.uri.fsPath).replace(/\.py$/, '');
var location = path.dirname(l.uri.fsPath);
while(fs.existsSync(path.join(location, '__init__.py'))) {
pymodule = path.basename(location) + '.' + pymodule;
location = path.dirname(location);
}
return pymodule;
}

export function addImport(ed: vscode.TextEditor, import_string: string) {
return ed.edit((b: vscode.TextEditorEdit) => b.insert(
getPositionForNewImport(import_string),
import_string + '\n'
));
}


export function getPositionForNewImport(import_string: string): vscode.Position {
// TODO: figure out better position:
return new vscode.Position(0, 0);
}
81 changes: 81 additions & 0 deletions src/test/extension.autoimport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as assert from 'assert';
import * as sinon from 'sinon';
import * as vscode from 'vscode';
import * as path from 'path';
import { AutoImportProvider } from './../client/providers/autoImportProvider';

let testPath = path.join(__dirname, '../../src/test');
const fileOne = path.join(testPath, 'pythonFiles/autoimport/one.py');
const fileThree = path.join(testPath, 'pythonFiles/autoimport/two/three.py');

let fileOneLoc = new vscode.Location(vscode.Uri.file(fileOne), new vscode.Position(0, 0));
let fileThreeLoc = new vscode.Location(vscode.Uri.file(fileThree), new vscode.Position(0, 0));


suite('Autoimport', () => {
let autoimp = new AutoImportProvider();
let lookupSymbol = sinon.stub(autoimp, 'lookupSymbol');
let showChoices = sinon.stub(autoimp, 'showChoices');

suiteSetup(() => {
});

setup(() => {
lookupSymbol.reset();
showChoices.reset();
return vscode.workspace.openTextDocument(fileOne).then(vscode.window.showTextDocument);
});

test('choices are filtered and displayed"', done => {
lookupSymbol.resolves([
new vscode.SymbolInformation(
'TestClass', vscode.SymbolKind.Class, '', fileOneLoc
),
new vscode.SymbolInformation(
'TestClassTwo', vscode.SymbolKind.Class, '', fileOneLoc
),
new vscode.SymbolInformation(
'TestClass', vscode.SymbolKind.Namespace, '', fileOneLoc
),
]);

showChoices.resolves(undefined);

autoimp.autoImport('TestClass').then(function() {
assert(lookupSymbol.calledWith('TestClass'));
assert(showChoices.calledWith(['from one import TestClass']));
done();
});
});

test('module under a package"', done => {
lookupSymbol.resolves([
new vscode.SymbolInformation(
'TestClass', vscode.SymbolKind.Class, '', fileThreeLoc
),
]);

showChoices.resolves(undefined);

autoimp.autoImport('TestClass').then(function() {
assert(showChoices.calledWith(['from two.three import TestClass']));
done();
});
});

test('selection is added at line one', done => {
lookupSymbol.resolves([
new vscode.SymbolInformation(
'TestClass', vscode.SymbolKind.Class, '', fileOneLoc
),
]);

showChoices.resolves('from one import TestClass');

autoimp.autoImport('TestClass').then(function() {
let line0 = vscode.window.activeTextEditor.document.lineAt(0);
assert.equal(line0.text, 'from one import TestClass');
done();
});
});
});
Empty file.
Empty file.
Empty file.

0 comments on commit 0b4dbcb

Please sign in to comment.