Skip to content
This repository was archived by the owner on Jul 15, 2023. It is now read-only.

Commit e7e56ea

Browse files
karthikraobrramya-rao-a
authored andcommitted
Sort import packages in the Go: Add Import cmd by std lib first (#2803)
1 parent 578a3c5 commit e7e56ea

File tree

4 files changed

+56
-37
lines changed

4 files changed

+56
-37
lines changed

src/goImport.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@ export async function listPackages(excludeImportedPkgs: boolean = false): Promis
2020
? await getImports(vscode.window.activeTextEditor.document)
2121
: [];
2222
const pkgMap = await getImportablePackages(vscode.window.activeTextEditor.document.fileName, true);
23-
24-
return Array.from(pkgMap.keys())
25-
.filter(pkg => !importedPkgs.some(imported => imported === pkg))
26-
.sort();
23+
const stdLibs: string[] = [];
24+
const nonStdLibs: string[] = [];
25+
pkgMap.forEach((value, key) => {
26+
if (importedPkgs.some(imported => imported === key)) {
27+
return;
28+
}
29+
if (value.isStd) {
30+
stdLibs.push(key);
31+
} else {
32+
nonStdLibs.push(key);
33+
}
34+
});
35+
return [...stdLibs.sort(), ...nonStdLibs.sort()];
2736
}
2837

2938
/**
@@ -100,15 +109,15 @@ export function getTextEditForAddImport(arg: string): vscode.TextEdit[] {
100109
}
101110
}
102111

103-
export function addImport(arg: {importPath: string, from: string}) {
112+
export function addImport(arg: { importPath: string, from: string }) {
104113
const p = (arg && arg.importPath) ? Promise.resolve(arg.importPath) : askUserForImport();
105114
p.then(imp => {
106115
/* __GDPR__
107116
"addImportCmd" : {
108117
"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
109118
}
110119
*/
111-
sendTelemetryEvent('addImportCmd', { from: (arg && arg.from) || 'cmd'});
120+
sendTelemetryEvent('addImportCmd', { from: (arg && arg.from) || 'cmd' });
112121
const edits = getTextEditForAddImport(imp);
113122
if (edits && edits.length > 0) {
114123
const edit = new vscode.WorkspaceEdit();

src/goPackages.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ import { promptForMissingTool, promptForUpdatingTool } from './goInstallTools';
1010
import { envPath, fixDriveCasingInWindows, getCurrentGoWorkspaceFromGOPATH } from './goPath';
1111
import { getBinPath, getCurrentGoPath, getGoVersion, getToolsEnvVars, isVendorSupported, sendTelemetryEvent } from './util';
1212

13-
type GopkgsDone = (res: Map<string, string>) => void;
13+
type GopkgsDone = (res: Map<string, PackageInfo>) => void;
1414
interface Cache {
15-
entry: Map<string, string>;
15+
entry: Map<string, PackageInfo>;
1616
lastHit: number;
1717
}
1818

19+
export interface PackageInfo {
20+
name: string;
21+
isStd: boolean;
22+
}
23+
1924
let gopkgsNotified: boolean = false;
2025
let cacheTimeout: number = 5000;
2126

@@ -26,16 +31,16 @@ const allPkgsCache: Map<string, Cache> = new Map<string, Cache>();
2631

2732
const pkgRootDirs = new Map<string, string>();
2833

29-
function gopkgs(workDir?: string): Promise<Map<string, string>> {
34+
function gopkgs(workDir?: string): Promise<Map<string, PackageInfo>> {
3035
const gopkgsBinPath = getBinPath('gopkgs');
3136
if (!path.isAbsolute(gopkgsBinPath)) {
3237
promptForMissingTool('gopkgs');
33-
return Promise.resolve(new Map<string, string>());
38+
return Promise.resolve(new Map<string, PackageInfo>());
3439
}
3540

3641
const t0 = Date.now();
37-
return new Promise<Map<string, string>>((resolve, reject) => {
38-
const args = ['-format', '{{.Name}};{{.ImportPath}}'];
42+
return new Promise<Map<string, PackageInfo>>((resolve, reject) => {
43+
const args = ['-format', '{{.Name}};{{.ImportPath}};{{.Dir}}'];
3944
if (workDir) {
4045
args.push('-workDir', workDir);
4146
}
@@ -48,7 +53,7 @@ function gopkgs(workDir?: string): Promise<Map<string, string>> {
4853
cmd.stderr.on('data', d => errchunks.push(d));
4954
cmd.on('error', e => err = e);
5055
cmd.on('close', () => {
51-
const pkgs = new Map<string, string>();
56+
const pkgs = new Map<string, PackageInfo>();
5257
if (err && err.code === 'ENOENT') {
5358
return promptForMissingTool('gopkgs');
5459
}
@@ -64,7 +69,7 @@ function gopkgs(workDir?: string): Promise<Map<string, string>> {
6469
console.log(`Running gopkgs failed with "${errorMsg}"\nCheck if you can run \`gopkgs -format {{.Name}};{{.ImportPath}}\` in a terminal successfully.`);
6570
return resolve(pkgs);
6671
}
67-
72+
const goroot = process.env['GOROOT'];
6873
const output = chunks.join('');
6974
if (output.indexOf(';') === -1) {
7075
// User might be using the old gopkgs tool, prompt to update
@@ -75,19 +80,23 @@ function gopkgs(workDir?: string): Promise<Map<string, string>> {
7580
}
7681
const index = pkgPath.lastIndexOf('/');
7782
const pkgName = index === -1 ? pkgPath : pkgPath.substr(index + 1);
78-
pkgs.set(pkgPath, pkgName);
83+
pkgs.set(pkgPath, {
84+
name: pkgName,
85+
isStd: !pkgPath.includes('.')
86+
});
7987
});
8088
return resolve(pkgs);
8189
}
82-
8390
output.split('\n').forEach((pkgDetail) => {
8491
if (!pkgDetail || !pkgDetail.trim() || pkgDetail.indexOf(';') === -1) {
8592
return;
8693
}
87-
const [pkgName, pkgPath] = pkgDetail.trim().split(';');
88-
pkgs.set(pkgPath, pkgName);
94+
const [pkgName, pkgPath, pkgDir] = pkgDetail.trim().split(';');
95+
pkgs.set(pkgPath, {
96+
name: pkgName,
97+
isStd: goroot === null ? false : pkgDir.startsWith(goroot)
98+
});
8999
});
90-
91100
const timeTaken = Date.now() - t0;
92101
/* __GDPR__
93102
"gopkgs" : {
@@ -102,10 +111,10 @@ function gopkgs(workDir?: string): Promise<Map<string, string>> {
102111
});
103112
}
104113

105-
function getAllPackagesNoCache(workDir: string): Promise<Map<string, string>> {
106-
return new Promise<Map<string, string>>((resolve, reject) => {
114+
function getAllPackagesNoCache(workDir: string): Promise<Map<string, PackageInfo>> {
115+
return new Promise<Map<string, PackageInfo>>((resolve, reject) => {
107116
// Use subscription style to guard costly/long running invocation
108-
const callback = function(pkgMap: Map<string, string>) {
117+
const callback = function(pkgMap: Map<string, PackageInfo>) {
109118
resolve(pkgMap);
110119
};
111120

@@ -134,7 +143,7 @@ function getAllPackagesNoCache(workDir: string): Promise<Map<string, string>> {
134143
* @argument workDir. The workspace directory of the project.
135144
* @returns Map<string, string> mapping between package import path and package name
136145
*/
137-
export async function getAllPackages(workDir: string): Promise<Map<string, string>> {
146+
export async function getAllPackages(workDir: string): Promise<Map<string, PackageInfo>> {
138147
const cache = allPkgsCache.get(workDir);
139148
const useCache = cache && (new Date().getTime() - cache.lastHit) < cacheTimeout;
140149
if (useCache) {
@@ -163,32 +172,32 @@ export async function getAllPackages(workDir: string): Promise<Map<string, strin
163172
* @param useCache. Force to use cache
164173
* @returns Map<string, string> mapping between package import path and package name
165174
*/
166-
export function getImportablePackages(filePath: string, useCache: boolean = false): Promise<Map<string, string>> {
175+
export function getImportablePackages(filePath: string, useCache: boolean = false): Promise<Map<string, PackageInfo>> {
167176
filePath = fixDriveCasingInWindows(filePath);
168177
const fileDirPath = path.dirname(filePath);
169178

170179
let foundPkgRootDir = pkgRootDirs.get(fileDirPath);
171180
const workDir = foundPkgRootDir || fileDirPath;
172181
const cache = allPkgsCache.get(workDir);
173182

174-
const getAllPackagesPromise: Promise<Map<string, string>> = useCache && cache
183+
const getAllPackagesPromise: Promise<Map<string, PackageInfo>> = useCache && cache
175184
? Promise.race([getAllPackages(workDir), cache.entry])
176185
: getAllPackages(workDir);
177186

178187
return Promise.all([isVendorSupported(), getAllPackagesPromise]).then(([vendorSupported, pkgs]) => {
179-
const pkgMap = new Map<string, string>();
188+
const pkgMap = new Map<string, PackageInfo>();
180189
if (!pkgs) {
181190
return pkgMap;
182191
}
183192

184193
const currentWorkspace = getCurrentGoWorkspaceFromGOPATH(getCurrentGoPath(), fileDirPath);
185-
pkgs.forEach((pkgName, pkgPath) => {
186-
if (pkgName === 'main') {
194+
pkgs.forEach((info, pkgPath) => {
195+
if (info.name === 'main') {
187196
return;
188197
}
189198

190199
if (!vendorSupported || !currentWorkspace) {
191-
pkgMap.set(pkgPath, pkgName);
200+
pkgMap.set(pkgPath, info);
192201
return;
193202
}
194203

@@ -208,7 +217,7 @@ export function getImportablePackages(filePath: string, useCache: boolean = fals
208217

209218
const allowToImport = isAllowToImportPackage(fileDirPath, currentWorkspace, relativePkgPath);
210219
if (allowToImport) {
211-
pkgMap.set(relativePkgPath, pkgName);
220+
pkgMap.set(relativePkgPath, info);
212221
}
213222
});
214223
return pkgMap;

src/goSuggest.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import cp = require('child_process');
1111
import { getTextEditForAddImport } from './goImport';
1212
import { promptForMissingTool, promptForUpdatingTool } from './goInstallTools';
1313
import { isModSupported } from './goModules';
14-
import { getImportablePackages } from './goPackages';
14+
import { getImportablePackages, PackageInfo } from './goPackages';
1515
import { getCurrentGoWorkspaceFromGOPATH } from './goPath';
1616
import { byteOffsetAt, getBinPath, getCurrentGoPath, getGoConfig, getParametersAndReturnType, getToolsEnvVars, goBuiltinTypes, goKeywords, guessPackageNameFromFile, isPositionInComment, isPositionInString, parseFilePrelude, runGodoc } from './util';
1717

@@ -58,7 +58,7 @@ const exportedMemberRegex = /(const|func|type|var)(\s+\(.*\))?\s+([A-Z]\w*)/;
5858
const gocodeNoSupportForgbMsgKey = 'dontshowNoSupportForgb';
5959

6060
export class GoCompletionItemProvider implements vscode.CompletionItemProvider, vscode.Disposable {
61-
private pkgsList = new Map<string, string>();
61+
private pkgsList = new Map<string, PackageInfo>();
6262
private killMsgShown: boolean = false;
6363
private setGocodeOptions: boolean = true;
6464
private isGoMod: boolean = false;
@@ -467,8 +467,8 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider,
467467
*/
468468
private getPackageImportPath(input: string): string[] {
469469
const matchingPackages: any[] = [];
470-
this.pkgsList.forEach((pkgName: string, pkgPath: string) => {
471-
if (input === pkgName) {
470+
this.pkgsList.forEach((info: PackageInfo, pkgPath: string) => {
471+
if (input === info.name) {
472472
matchingPackages.push(pkgPath);
473473
}
474474
});
@@ -528,15 +528,16 @@ function getKeywordCompletions(currentWord: string): vscode.CompletionItem[] {
528528
* @param allPkgMap Map of all available packages and their import paths
529529
* @param importedPackages List of imported packages. Used to prune imported packages out of available packages
530530
*/
531-
function getPackageCompletions(document: vscode.TextDocument, currentWord: string, allPkgMap: Map<string, string>, importedPackages: string[] = []): vscode.CompletionItem[] {
531+
function getPackageCompletions(document: vscode.TextDocument, currentWord: string, allPkgMap: Map<string, PackageInfo>, importedPackages: string[] = []): vscode.CompletionItem[] {
532532
const cwd = path.dirname(document.fileName);
533533
const goWorkSpace = getCurrentGoWorkspaceFromGOPATH(getCurrentGoPath(), cwd);
534534
const workSpaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
535535
const currentPkgRootPath = (workSpaceFolder ? workSpaceFolder.uri.path : cwd).slice(goWorkSpace.length + 1);
536536

537537
const completionItems: any[] = [];
538538

539-
allPkgMap.forEach((pkgName: string, pkgPath: string) => {
539+
allPkgMap.forEach((info: PackageInfo, pkgPath: string) => {
540+
const pkgName = info.name;
540541
if (pkgName.startsWith(currentWord) && importedPackages.indexOf(pkgName) === -1) {
541542

542543
const item = new vscode.CompletionItem(pkgName, vscode.CompletionItemKind.Keyword);

test/integration/extension.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ It returns the number of bytes written and any write error encountered.
552552

553553
vendorSupportPromise.then(async (vendorSupport: boolean) => {
554554
const gopkgsPromise = getAllPackages(workDir).then(pkgMap => {
555-
const pkgs = Array.from(pkgMap.keys()).filter(p => pkgMap.get(p) !== 'main');
555+
const pkgs = Array.from(pkgMap.keys()).filter(p => pkgMap.get(p).name !== 'main');
556556
if (vendorSupport) {
557557
vendorPkgsFullPath.forEach(pkg => {
558558
assert.equal(pkgs.indexOf(pkg) > -1, true, `Package not found by goPkgs: ${pkg}`);

0 commit comments

Comments
 (0)