diff --git a/src/goSuggest.ts b/src/goSuggest.ts index d6c5456c0..bd8314f6f 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -117,11 +117,11 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { if (suggestions.length === 0 && lineTillCurrentPosition.endsWith('.')) { let pkgPath = this.getPackagePathFromLine(lineTillCurrentPosition); - if (pkgPath) { + if (pkgPath.length === 1) { // Now that we have the package path, import it right after the "package" statement let { imports, pkg } = parseFilePrelude(vscode.window.activeTextEditor.document.getText()); let posToAddImport = document.offsetAt(new vscode.Position(pkg.start + 1, 0)); - let textToAdd = `import "${pkgPath}"\n`; + let textToAdd = `import "${pkgPath[0]}"\n`; inputText = inputText.substr(0, posToAddImport) + textToAdd + inputText.substr(posToAddImport); offset += textToAdd.length; @@ -131,11 +131,28 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { // add additionalTextEdits to do the same in the actual document in the editor // We use additionalTextEdits instead of command so that 'useCodeSnippetsOnFunctionSuggest' feature continues to work newsuggestions.forEach(item => { - item.additionalTextEdits = getTextEditForAddImport(pkgPath); + item.additionalTextEdits = getTextEditForAddImport(pkgPath[0]); }); resolve(newsuggestions); }, reject); } + if (pkgPath.length > 1) { + pkgPath.forEach(pkg => { + let item = new vscode.CompletionItem( + `${lineTillCurrentPosition.replace('.', '').trim()} (${pkg})`, + vscode.CompletionItemKind.Module + ); + item.additionalTextEdits = getTextEditForAddImport(pkg); + item.insertText = ''; + item.detail = pkg; + item.command = { + title: 'Trigger Suggest', + command: 'editor.action.triggerSuggest' + }; + suggestions.push(item); + }); + resolve(suggestions); + } } resolve(suggestions); }, reject); @@ -396,7 +413,7 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { } // Given a line ending with dot, return the word preceeding the dot if it is a package name that can be imported - private getPackagePathFromLine(line: string): string { + private getPackagePathFromLine(line: string): string[] { let pattern = /(\w+)\.$/g; let wordmatches = pattern.exec(line); if (!wordmatches) { @@ -411,9 +428,6 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { matchingPackages.push(pkgPath); } }); - - if (matchingPackages && matchingPackages.length === 1) { - return matchingPackages[0]; - } + return matchingPackages; } } diff --git a/test/fixtures/completions/unimportedMultiplePkgs.go b/test/fixtures/completions/unimportedMultiplePkgs.go new file mode 100644 index 000000000..28bfbc796 --- /dev/null +++ b/test/fixtures/completions/unimportedMultiplePkgs.go @@ -0,0 +1,5 @@ +package main + +func main() { + template. +} diff --git a/test/fixtures/fillStruct/golden_2.go b/test/fixtures/fillStruct/golden_2.go index 5f5b8ed5b..540a45752 100644 --- a/test/fixtures/fillStruct/golden_2.go +++ b/test/fixtures/fillStruct/golden_2.go @@ -7,7 +7,7 @@ import ( func main() { _ = http.Client{ Transport: nil, - CheckRedirect: nil, + CheckRedirect: func(*http.Request, []*http.Request) error { panic("not implemented") }, Jar: nil, Timeout: 0, } diff --git a/test/go.test.ts b/test/go.test.ts index ce5822576..36f6480de 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -66,6 +66,7 @@ suite('Go Extension Tests', () => { fs.copySync(path.join(fixtureSourcePath, 'buildTags', 'hello.go'), path.join(fixturePath, 'buildTags', 'hello.go')); fs.copySync(path.join(fixtureSourcePath, 'testTags', 'hello_test.go'), path.join(fixturePath, 'testTags', 'hello_test.go')); fs.copySync(path.join(fixtureSourcePath, 'completions', 'unimportedPkgs.go'), path.join(fixturePath, 'completions', 'unimportedPkgs.go')); + fs.copySync(path.join(fixtureSourcePath, 'completions', 'unimportedMultiplePkgs.go'), path.join(fixturePath, 'completions', 'unimportedMultiplePkgs.go')); fs.copySync(path.join(fixtureSourcePath, 'completions', 'snippets.go'), path.join(fixturePath, 'completions', 'snippets.go')); fs.copySync(path.join(fixtureSourcePath, 'completions', 'nosnippets.go'), path.join(fixturePath, 'completions', 'nosnippets.go')); fs.copySync(path.join(fixtureSourcePath, 'completions', 'exportedMemberDocs.go'), path.join(fixturePath, 'completions', 'exportedMemberDocs.go')); @@ -948,6 +949,41 @@ It returns the number of bytes written and any write error encountered. }).then(() => done(), done); }); + test('Test Completion on unimported packages (multiple)', (done) => { + let config = Object.create(vscode.workspace.getConfiguration('go'), {}); + let provider = new GoCompletionItemProvider(); + let position = new vscode.Position(3, 14); + let expectedItems = [ + { + label: 'template (html/template)', + import: '\nimport (\n\t"html/template"\n)\n' + }, + { + label: 'template (text/template)', + import: '\nimport (\n\t"text/template"\n)\n' + } + ]; + let uri = vscode.Uri.file(path.join(fixturePath, 'completions', 'unimportedMultiplePkgs.go')); + vscode.workspace.openTextDocument(uri).then((textDocument) => { + return vscode.window.showTextDocument(textDocument).then(editor => { + return provider.provideCompletionItemsInternal(editor.document, position, null, config).then(items => { + let labels = items.map(x => x.label); + expectedItems.forEach(expectedItem => { + const actualItem: vscode.CompletionItem = items.filter(item => item.label === expectedItem.label)[0]; + if (!actualItem) { + assert.fail(actualItem, expectedItem, `Missing expected item in completion list: ${expectedItem.label} Actual: ${labels}`); + return; + } + assert.equal(actualItem.additionalTextEdits.length, 1); + assert.equal(actualItem.additionalTextEdits[0].newText, expectedItem.import); + }); + }).then(() => vscode.commands.executeCommand('workbench.action.closeActiveEditor')); + }); + }, (err) => { + assert.ok(false, `error in OpenTextDocument ${err}`); + }).then(() => done(), done); + }); + test('Test Completion on Comments for Exported Members', (done) => { let provider = new GoCompletionItemProvider(); let testCases: [vscode.Position, string[]][] = [