diff --git a/src/goImport.ts b/src/goImport.ts index 3dbb6709c..8572dcda7 100644 --- a/src/goImport.ts +++ b/src/goImport.ts @@ -14,15 +14,15 @@ import { getImportablePackages } from './goPackages'; const missingToolMsg = 'Missing tool: '; -export function listPackages(excludeImportedPkgs: boolean = false): Promise { - const importsPromise = excludeImportedPkgs && vscode.window.activeTextEditor ? getImports(vscode.window.activeTextEditor.document) : Promise.resolve([]); - const pkgsPromise = getImportablePackages(vscode.window.activeTextEditor.document.fileName, true); - return Promise.all([pkgsPromise, importsPromise]).then(([pkgMap, importedPkgs]) => { - importedPkgs.forEach(pkg => { - pkgMap.delete(pkg); - }); - return Array.from(pkgMap.keys()).sort(); - }); +export async function listPackages(excludeImportedPkgs: boolean = false): Promise { + const importedPkgs = excludeImportedPkgs && vscode.window.activeTextEditor + ? await getImports(vscode.window.activeTextEditor.document) + : []; + const pkgMap = await getImportablePackages(vscode.window.activeTextEditor.document.fileName, true); + + return Array.from(pkgMap.keys()) + .filter(pkg => !importedPkgs.some(imported => imported === pkg)) + .sort(); } /** @@ -32,13 +32,13 @@ export function listPackages(excludeImportedPkgs: boolean = false): Promise { - const options = { fileName: document.fileName, importsOption: GoOutlineImportsOptions.Only, document, skipRanges: true }; + const options = { fileName: document.fileName, importsOption: GoOutlineImportsOptions.Only, document }; const symbols = await documentSymbols(options, null); if (!symbols || !symbols.length) { return []; } // import names will be of the form "math", so strip the quotes in the beginning and the end - let imports = symbols + let imports = symbols[0].children .filter(x => x.kind === vscode.SymbolKind.Namespace) .map(x => x.name.substr(1, x.name.length - 2)); return imports; diff --git a/src/goOutline.ts b/src/goOutline.ts index 3baa64a0a..3468f18c5 100644 --- a/src/goOutline.ts +++ b/src/goOutline.ts @@ -51,11 +51,6 @@ export interface GoOutlineOptions { */ document?: vscode.TextDocument; - /** - * Skips range information in the output. - * Calculating ranges is slightly expensive for large files, therefore skip it when not required. - */ - skipRanges?: boolean; } export async function documentSymbols(options: GoOutlineOptions, token: vscode.CancellationToken): Promise { @@ -63,15 +58,13 @@ export async function documentSymbols(options: GoOutlineOptions, token: vscode.C return convertToCodeSymbols(options.document, decls, options.importsOption !== GoOutlineImportsOptions.Exclude, - (options.skipRanges || !options.document) - ? null - : makeMemoizedByteOffsetConverter(new Buffer(options.document.getText()))); + makeMemoizedByteOffsetConverter(Buffer.from(options.document.getText()))); } export function runGoOutline(options: GoOutlineOptions, token: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { - let gooutline = getBinPath('go-outline'); - let gooutlineFlags = ['-f', options.fileName]; + const gooutline = getBinPath('go-outline'); + const gooutlineFlags = ['-f', options.fileName]; if (options.importsOption === GoOutlineImportsOptions.Only) { gooutlineFlags.push('-imports-only'); } @@ -133,7 +126,7 @@ function convertToCodeSymbols( includeImports: boolean, byteOffsetToDocumentOffset: (byteOffset: number) => number): vscode.DocumentSymbol[] { - let symbols: vscode.DocumentSymbol[] = []; + const symbols: vscode.DocumentSymbol[] = []; (decls || []).forEach(decl => { if (!includeImports && decl.type === 'import') return; @@ -146,26 +139,22 @@ function convertToCodeSymbols( } - let selectionRange = null; - let symbolRange = null; - if (document && byteOffsetToDocumentOffset) { - const start = byteOffsetToDocumentOffset(decl.start - 1); - const end = byteOffsetToDocumentOffset(decl.end - 1); - const startPosition = document.positionAt(start); - const endPosition = document.positionAt(end); - symbolRange = new vscode.Range(startPosition, endPosition); - selectionRange = startPosition.line === endPosition.line ? - symbolRange : - new vscode.Range(startPosition, document.lineAt(startPosition.line).range.end); - - if (decl.type === 'type') { - let line = document.lineAt(document.positionAt(start)); - let regex = new RegExp(`^\\s*type\\s+${decl.label}\\s+struct\\b`); - decl.type = regex.test(line.text) ? 'struct' : 'type'; - } + const start = byteOffsetToDocumentOffset(decl.start - 1); + const end = byteOffsetToDocumentOffset(decl.end - 1); + const startPosition = document.positionAt(start); + const endPosition = document.positionAt(end); + const symbolRange = new vscode.Range(startPosition, endPosition); + const selectionRange = startPosition.line === endPosition.line ? + symbolRange : + new vscode.Range(startPosition, document.lineAt(startPosition.line).range.end); + if (decl.type === 'type') { + let line = document.lineAt(document.positionAt(start)); + let regex = new RegExp(`^\\s*type\\s+${decl.label}\\s+struct\\b`); + decl.type = regex.test(line.text) ? 'struct' : 'type'; } - let symbolInfo = new vscode.DocumentSymbol( + + const symbolInfo = new vscode.DocumentSymbol( label, decl.type, goKindToCodeKind[decl.type], @@ -188,7 +177,11 @@ export class GoDocumentSymbolProvider implements vscode.DocumentSymbolProvider { const gotoSymbolConfig = vscode.workspace.getConfiguration('go', document.uri)['gotoSymbol']; this.includeImports = gotoSymbolConfig ? gotoSymbolConfig['includeImports'] : false; } - const options = { fileName: document.fileName, document: document, importsOption: this.includeImports ? GoOutlineImportsOptions.Include : GoOutlineImportsOptions.Exclude }; + const options: GoOutlineOptions = { + fileName: document.fileName, + document, + importsOption: this.includeImports ? GoOutlineImportsOptions.Include : GoOutlineImportsOptions.Exclude + }; return documentSymbols(options, token); } } diff --git a/test/go.test.ts b/test/go.test.ts index 100e2cd7e..93623bdbd 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -382,33 +382,30 @@ It returns the number of bytes written and any write error encountered. return done(); } - getGoVersion().then(version => { + getGoVersion().then(async version => { if (version && version.major === 1 && version.minor < 6) { // gotests is not supported in Go 1.5, so skip the test return Promise.resolve(); } let uri = vscode.Uri.file(path.join(generatePackageTestSourcePath, 'generatetests.go')); - return vscode.workspace.openTextDocument(uri).then(document => { - return vscode.window.showTextDocument(document).then(editor => { - return generateTestCurrentPackage().then((result: boolean) => { - assert.equal(result, true); - return Promise.resolve(); - }); - }); - }).then(() => { - vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - if (fs.existsSync(path.join(generateTestsSourcePath, 'generatetests_test.go'))) { - return Promise.resolve(); - } else { - return Promise.reject('generatetests_test.go not found'); - } - }); + const document = await vscode.workspace.openTextDocument(uri); + const editor = await vscode.window.showTextDocument(document); + const result = await generateTestCurrentPackage(); + assert.equal(result, true); + await Promise.resolve(); + vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + if (fs.existsSync(path.join(generateTestsSourcePath, 'generatetests_test.go'))) { + return Promise.resolve(); + } + else { + return Promise.reject('generatetests_test.go not found'); + } }).then(() => done(), done); }); test('Gometalinter error checking', (done) => { - getGoVersion().then(version => { + getGoVersion().then(async version => { if (version && version.major === 1 && version.minor < 6) { // golint in gometalinter is not supported in Go 1.5, so skip the test return Promise.resolve(); @@ -426,31 +423,28 @@ It returns the number of bytes written and any write error encountered. { line: 11, severity: 'warning', msg: 'unused variable or constant undeclared name: prin (varcheck)' }, ]; let errorsTestPath = path.join(fixturePath, 'errorsTest', 'errors.go'); - return check(vscode.Uri.file(errorsTestPath), config).then(diagnostics => { - const allDiagnostics = [].concat.apply([], diagnostics.map(x => x.errors)); - let sortedDiagnostics = allDiagnostics.sort((a: any, b: any) => { - if (a.msg < b.msg) - return -1; - if (a.msg > b.msg) - return 1; - return 0; - }); - - assert.equal(sortedDiagnostics.length > 0, true, `Failed to get linter results`); - let matchCount = 0; - for (let i in expected) { - for (let j in sortedDiagnostics) { - if ((expected[i].line === sortedDiagnostics[j].line) - && (expected[i].severity === sortedDiagnostics[j].severity) - && (expected[i].msg === sortedDiagnostics[j].msg)) { - matchCount++; - } + const diagnostics = await check(vscode.Uri.file(errorsTestPath), config); + const allDiagnostics = [].concat.apply([], diagnostics.map(x => x.errors)); + let sortedDiagnostics = allDiagnostics.sort((a: any, b: any) => { + if (a.msg < b.msg) + return -1; + if (a.msg > b.msg) + return 1; + return 0; + }); + assert.equal(sortedDiagnostics.length > 0, true, `Failed to get linter results`); + let matchCount = 0; + for (let i in expected) { + for (let j in sortedDiagnostics) { + if ((expected[i].line === sortedDiagnostics[j].line) + && (expected[i].severity === sortedDiagnostics[j].severity) + && (expected[i].msg === sortedDiagnostics[j].msg)) { + matchCount++; } } - assert.equal(matchCount >= expected.length, true, `Failed to match expected errors`); - - return Promise.resolve(); - }); + } + assert.equal(matchCount >= expected.length, true, `Failed to match expected errors`); + return Promise.resolve(); }).then(() => done(), done); }); @@ -555,39 +549,46 @@ It returns the number of bytes written and any write error encountered. }); test('Test Outline', (done) => { - const filePath = path.join(fixturePath, 'outlineTest', 'test.go'); - const options = { fileName: filePath, importsOption: GoOutlineImportsOptions.Include, skipRanges: true }; - documentSymbols(options, null).then(outlines => { - const packageSymbols = outlines.filter(x => x.kind === vscode.SymbolKind.Package); - const imports = outlines.filter(x => x.kind === vscode.SymbolKind.Namespace); - const functions = outlines.filter(x => x.kind === vscode.SymbolKind.Function); - - assert.equal(packageSymbols.length, 1); - assert.equal(packageSymbols[0].name, 'main'); - assert.equal(imports.length, 1); - assert.equal(imports[0].name, '"fmt"'); - assert.equal(functions.length, 2); - assert.equal(functions[0].name, 'print'); - assert.equal(functions[1].name, 'main'); - done(); - }, done); + const uri = vscode.Uri.file(path.join(fixturePath, 'outlineTest', 'test.go')); + vscode.workspace.openTextDocument(uri).then(document => { + const options = { document: document, fileName: document.fileName, importsOption: GoOutlineImportsOptions.Include }; + + documentSymbols(options, null).then(outlines => { + const packageSymbols = outlines.filter(x => x.kind === vscode.SymbolKind.Package); + const imports = outlines[0].children.filter(x => x.kind === vscode.SymbolKind.Namespace); + const functions = outlines[0].children.filter(x => x.kind === vscode.SymbolKind.Function); + + assert.equal(packageSymbols.length, 1); + assert.equal(packageSymbols[0].name, 'main'); + assert.equal(imports.length, 1); + assert.equal(imports[0].name, '"fmt"'); + assert.equal(functions.length, 2); + assert.equal(functions[0].name, 'print'); + assert.equal(functions[1].name, 'main'); + done(); + }, done); + }); + }); test('Test Outline imports only', (done) => { - const filePath = path.join(fixturePath, 'outlineTest', 'test.go'); - const options = { fileName: filePath, importsOption: GoOutlineImportsOptions.Only, skipRanges: true }; - documentSymbols(options, null).then(outlines => { - const packageSymbols = outlines.filter(x => x.kind === vscode.SymbolKind.Package); - const imports = outlines.filter(x => x.kind === vscode.SymbolKind.Namespace); - const functions = outlines.filter(x => x.kind === vscode.SymbolKind.Function); - - assert.equal(packageSymbols.length, 1); - assert.equal(packageSymbols[0].name, 'main'); - assert.equal(imports.length, 1); - assert.equal(imports[0].name, '"fmt"'); - assert.equal(functions.length, 0); - done(); - }, done); + const uri = vscode.Uri.file(path.join(fixturePath, 'outlineTest', 'test.go')); + vscode.workspace.openTextDocument(uri).then(document => { + const options = { document: document, fileName: document.fileName, importsOption: GoOutlineImportsOptions.Only }; + + documentSymbols(options, null).then(outlines => { + const packageSymbols = outlines.filter(x => x.kind === vscode.SymbolKind.Package); + const imports = outlines[0].children.filter(x => x.kind === vscode.SymbolKind.Namespace); + const functions = outlines[0].children.filter(x => x.kind === vscode.SymbolKind.Function); + + assert.equal(packageSymbols.length, 1); + assert.equal(packageSymbols[0].name, 'main'); + assert.equal(imports.length, 1); + assert.equal(imports[0].name, '"fmt"'); + assert.equal(functions.length, 0); + done(); + }, done); + }); }); test('Test Outline document symbols', (done) => { @@ -616,13 +617,11 @@ It returns the number of bytes written and any write error encountered. test('Test listPackages', (done) => { const uri = vscode.Uri.file(path.join(fixturePath, 'test.go')); vscode.workspace.openTextDocument(uri).then(document => vscode.window.showTextDocument(document) - .then(editor => { - const includeImportedPkgs = listPackages(false); - const excludeImportedPkgs = listPackages(true); - return Promise.all([includeImportedPkgs, excludeImportedPkgs]).then(([pkgsInclude, pkgsExclude]) => { - assert.equal(pkgsInclude.indexOf('fmt') > -1, true); - assert.equal(pkgsExclude.indexOf('fmt') > -1, false); - }); + .then(async editor => { + const includeImportedPkgs = await listPackages(false); + const excludeImportedPkgs = await listPackages(true); + assert.equal(includeImportedPkgs.indexOf('fmt') > -1, true); + assert.equal(excludeImportedPkgs.indexOf('fmt') > -1, false); })).then(() => done(), done); });