@@ -9,31 +9,91 @@ import vscode = require('vscode');
99import cp = require( 'child_process' ) ;
1010import { getBinPath } from './goPath' ;
1111import { parseFilePrelude } from './util' ;
12- import { promptForMissingTool } from './goInstallTools' ;
1312import { documentSymbols } from './goOutline' ;
13+ import { promptForMissingTool , isVendorSupported } from './goInstallTools' ;
14+ import path = require( 'path' ) ;
1415
1516export function listPackages ( excludeImportedPkgs : boolean = false ) : Thenable < string [ ] > {
1617 let importsPromise = excludeImportedPkgs && vscode . window . activeTextEditor ? getImports ( vscode . window . activeTextEditor . document . fileName ) : Promise . resolve ( [ ] ) ;
17- let pkgsPromise = new Promise < string [ ] > ( ( resolve , reject ) => {
18+ let vendorSupportPromise = isVendorSupported ( ) ;
19+ let goPkgsPromise = new Promise < string [ ] > ( ( resolve , reject ) => {
1820 cp . execFile ( getBinPath ( 'gopkgs' ) , [ ] , ( err , stdout , stderr ) => {
1921 if ( err && ( < any > err ) . code === 'ENOENT' ) {
2022 promptForMissingTool ( 'gopkgs' ) ;
2123 return reject ( ) ;
2224 }
2325 let lines = stdout . toString ( ) . split ( '\n' ) ;
24- let sortedlines = lines . sort ( ) . slice ( 1 ) ; // Drop the empty entry from the final '\n'
25- return resolve ( sortedlines ) ;
26+ if ( lines [ lines . length - 1 ] === '' ) {
27+ // Drop the empty entry from the final '\n'
28+ lines . pop ( ) ;
29+ }
30+ return resolve ( lines ) ;
2631 } ) ;
2732 } ) ;
2833
29- return Promise . all < string [ ] > ( [ importsPromise , pkgsPromise ] ) . then ( values => {
30- let imports = values [ 0 ] ;
31- let pkgs = values [ 1 ] ;
32- if ( imports . length === 0 ) {
33- return pkgs ;
34- }
35- return pkgs . filter ( element => {
36- return imports . indexOf ( element ) === - 1 ;
34+ return vendorSupportPromise . then ( ( vendorSupport : boolean ) => {
35+ return Promise . all < string [ ] > ( [ goPkgsPromise , importsPromise ] ) . then ( values => {
36+ let pkgs = values [ 0 ] ;
37+ let importedPkgs = values [ 1 ] ;
38+
39+ if ( ! vendorSupport ) {
40+ if ( importedPkgs . length > 0 ) {
41+ pkgs = pkgs . filter ( element => {
42+ return importedPkgs . indexOf ( element ) === - 1 ;
43+ } ) ;
44+ }
45+ return pkgs . sort ( ) ;
46+ }
47+
48+ let currentFileDirPath = path . dirname ( vscode . window . activeTextEditor . document . fileName ) ;
49+ let workspaces : string [ ] = process . env [ 'GOPATH' ] . split ( path . delimiter ) ;
50+ let currentWorkspace = path . join ( workspaces [ 0 ] , 'src' ) ;
51+
52+ // Workaround for issue in https://github.com/Microsoft/vscode/issues/9448#issuecomment-244804026
53+ if ( process . platform === 'win32' ) {
54+ currentFileDirPath = currentFileDirPath . substr ( 0 , 1 ) . toUpperCase ( ) + currentFileDirPath . substr ( 1 ) ;
55+ }
56+
57+ // In case of multiple workspaces, find current workspace by checking if current file is
58+ // under any of the workspaces in $GOPATH
59+ for ( let i = 1 ; i < workspaces . length ; i ++ ) {
60+ let possibleCurrentWorkspace = path . join ( workspaces [ i ] , 'src' ) ;
61+ if ( currentFileDirPath . startsWith ( possibleCurrentWorkspace ) ) {
62+ // In case of nested workspaces, (example: both /Users/me and /Users/me/src/a/b/c are in $GOPATH)
63+ // both parent & child workspace in the nested workspaces pair can make it inside the above if block
64+ // Therefore, the below check will take longer (more specific to current file) of the two
65+ if ( possibleCurrentWorkspace . length > currentWorkspace . length ) {
66+ currentWorkspace = possibleCurrentWorkspace ;
67+ }
68+ }
69+ }
70+
71+ let pkgSet = new Set < string > ( ) ;
72+ pkgs . forEach ( pkg => {
73+ if ( ! pkg || importedPkgs . indexOf ( pkg ) > - 1 ) {
74+ return ;
75+ }
76+
77+ let magicVendorString = '/vendor/' ;
78+ let vendorIndex = pkg . indexOf ( magicVendorString ) ;
79+
80+ // Check if current file and the vendor pkg belong to the same root project
81+ // If yes, then vendor pkg can be replaced with its relative path to the "vendor" folder
82+ if ( vendorIndex > 0 ) {
83+ let rootProjectForVendorPkg = path . join ( currentWorkspace , pkg . substr ( 0 , vendorIndex ) ) ;
84+ let relativePathForVendorPkg = pkg . substring ( vendorIndex + magicVendorString . length ) ;
85+
86+ if ( relativePathForVendorPkg && currentFileDirPath . startsWith ( rootProjectForVendorPkg ) ) {
87+ pkgSet . add ( relativePathForVendorPkg ) ;
88+ return ;
89+ }
90+ }
91+
92+ // pkg is not a vendor project or is a vendor project not belonging to current project
93+ pkgSet . add ( pkg ) ;
94+ } ) ;
95+
96+ return Array . from ( pkgSet ) . sort ( ) ;
3797 } ) ;
3898 } ) ;
3999}
0 commit comments