@@ -39,7 +39,7 @@ import { GoWorkspaceSymbolProvider } from './goSymbol';
3939import { getTool , Tool } from './goTools' ;
4040import { GoTypeDefinitionProvider } from './goTypeDefinition' ;
4141import { getFromGlobalState , updateGlobalState } from './stateUtils' ;
42- import { getBinPath , getCurrentGoPath , getGoConfig } from './util' ;
42+ import { getBinPath , getCurrentGoPath , getGoConfig , getGoVersion } from './util' ;
4343
4444interface LanguageServerConfig {
4545 serverName : string ;
@@ -84,22 +84,43 @@ export async function startLanguageServerWithFallback(ctx: vscode.ExtensionConte
8484 if ( activation && cfg . enabled && cfg . serverName === 'gopls' ) {
8585 const tool = getTool ( cfg . serverName ) ;
8686 if ( tool ) {
87- const versionToUpdate = await shouldUpdateLanguageServer ( tool , cfg . path , cfg . checkForUpdates ) ;
88- if ( versionToUpdate ) {
89- promptForUpdatingTool ( tool . name , versionToUpdate ) ;
90- } else if ( goplsSurveyOn ) {
91- // Only prompt users to fill out the gopls survey if we are not
92- // also prompting them to update (both would be too much).
93- const timeout = 1000 * 60 * 60 ; // 1 hour
94- setTimeout ( async ( ) => {
95- const surveyCfg = await maybePromptForGoplsSurvey ( ) ;
96- flushSurveyConfig ( surveyCfg ) ;
97- } , timeout ) ;
87+ // Skip the update prompt - the user should have a special generics
88+ // version of gopls.
89+ if ( false ) {
90+ const versionToUpdate = await shouldUpdateLanguageServer ( tool , cfg . path , cfg . checkForUpdates ) ;
91+ if ( versionToUpdate ) {
92+ promptForUpdatingTool ( tool . name , versionToUpdate ) ;
93+ } else if ( goplsSurveyOn ) {
94+ // Only prompt users to fill out the gopls survey if we are not
95+ // also prompting them to update (both would be too much).
96+ const timeout = 1000 * 60 * 60 ; // 1 hour
97+ setTimeout ( async ( ) => {
98+ const surveyCfg = await maybePromptForGoplsSurvey ( ) ;
99+ flushSurveyConfig ( surveyCfg ) ;
100+ } , timeout ) ;
101+ }
102+ }
103+ }
104+ }
105+
106+ // Run `go tool go2go help` to check if the user is working with a version
107+ // of Go that supports the generics prototype. This will error either way,
108+ // but we can check the error message to see if the command was recognized.
109+ let usingGo2Go : boolean = false ;
110+ const goRuntimePath = getBinPath ( 'go' ) ;
111+ if ( goRuntimePath ) {
112+ const execFile = util . promisify ( cp . execFile ) ;
113+ try {
114+ await execFile ( goRuntimePath , [ 'tool' , 'go2go' , 'help' ] , { env : cfg . env } ) ;
115+ } catch ( err ) {
116+ const errStr = `${ err } ` ;
117+ if ( errStr . indexOf ( 'Usage: go2go <command> [arguments]' ) !== - 1 ) {
118+ usingGo2Go = true ;
98119 }
99120 }
100121 }
101122
102- const started = await startLanguageServer ( ctx , cfg ) ;
123+ const started = await startLanguageServer ( ctx , cfg , usingGo2Go ) ;
103124
104125 // If the server has been disabled, or failed to start,
105126 // fall back to the default providers, while making sure not to
@@ -109,7 +130,8 @@ export async function startLanguageServerWithFallback(ctx: vscode.ExtensionConte
109130 }
110131}
111132
112- async function startLanguageServer ( ctx : vscode . ExtensionContext , config : LanguageServerConfig ) : Promise < boolean > {
133+ async function startLanguageServer (
134+ ctx : vscode . ExtensionContext , config : LanguageServerConfig , usingGo2Go : boolean ) : Promise < boolean > {
113135 // If the client has already been started, make sure to clear existing
114136 // diagnostics and stop it.
115137 if ( languageClient ) {
@@ -128,7 +150,7 @@ async function startLanguageServer(ctx: vscode.ExtensionContext, config: Languag
128150 // Track the latest config used to start the language server,
129151 // and rebuild the language client.
130152 latestConfig = config ;
131- languageClient = await buildLanguageClient ( config ) ;
153+ languageClient = await buildLanguageClient ( config , usingGo2Go ) ;
132154 }
133155
134156 // If the user has not enabled the language server, return early.
@@ -158,7 +180,7 @@ async function startLanguageServer(ctx: vscode.ExtensionContext, config: Languag
158180 return true ;
159181}
160182
161- async function buildLanguageClient ( config : LanguageServerConfig ) : Promise < LanguageClient > {
183+ async function buildLanguageClient ( config : LanguageServerConfig , usingGo2Go : boolean ) : Promise < LanguageClient > {
162184 // Reuse the same output channel for each instance of the server.
163185 if ( config . enabled && ! serverOutputChannel ) {
164186 serverOutputChannel = vscode . window . createOutputChannel ( config . serverName ) ;
@@ -173,12 +195,39 @@ async function buildLanguageClient(config: LanguageServerConfig): Promise<Langua
173195 } ,
174196 {
175197 initializationOptions : { } ,
176- documentSelector : [ 'go' , 'go.mod' , 'go.sum' ] ,
198+ documentSelector : [ 'go' , 'go2' , ' go.mod', 'go.sum' ] ,
177199 uriConverters : {
178200 // Apply file:/// scheme to all file paths.
179- code2Protocol : ( uri : vscode . Uri ) : string =>
180- ( uri . scheme ? uri : uri . with ( { scheme : 'file' } ) ) . toString ( ) ,
181- protocol2Code : ( uri : string ) => vscode . Uri . parse ( uri )
201+ code2Protocol : ( uri : vscode . Uri ) : string => {
202+ if ( usingGo2Go ) {
203+ uri = ( uri . scheme ? uri : uri . with ( { scheme : 'file' } ) ) ;
204+ // If the file has a *.go2 suffix, try stripping it.
205+ const uriPath = uri . path . replace ( '.go2' , '.go' ) ;
206+ uri = uri . with ( { path : uriPath } ) ;
207+ return uri . toString ( ) ;
208+ }
209+ return ( uri . scheme ? uri : uri . with ( { scheme : 'file' } ) ) . toString ( ) ;
210+ } ,
211+ protocol2Code : ( uri : string ) => {
212+ if ( usingGo2Go ) {
213+ const parsed = vscode . Uri . parse ( uri ) ;
214+ try {
215+ fs . statSync ( parsed . fsPath ) ;
216+ return parsed ;
217+ } catch ( err ) {
218+ // Try adding a 'go2' suffix to a Go file and see if it exists.
219+ const uriPath = parsed . fsPath . replace ( '.go' , '.go2' ) ;
220+ try {
221+ fs . statSync ( uriPath ) ;
222+ return parsed . with ( { path : parsed . path . replace ( '.go' , '.go2' ) } ) ;
223+ } catch ( err ) {
224+ // do nothing?
225+ }
226+ }
227+ return parsed ;
228+ }
229+ return vscode . Uri . parse ( uri ) ;
230+ } ,
182231 } ,
183232 outputChannel : serverOutputChannel ,
184233 revealOutputChannelOn : RevealOutputChannelOn . Never ,
@@ -494,7 +543,7 @@ export async function shouldUpdateLanguageServer(
494543
495544 // If the user's version does not contain a timestamp,
496545 // default to a semver comparison of the two versions.
497- const usersVersionSemver = semver . coerce ( usersVersion , { includePrerelease : true , loose : true } ) ;
546+ const usersVersionSemver = semver . coerce ( usersVersion , { includePrerelease : true , loose : true } ) ;
498547 return semver . lt ( usersVersionSemver , latestVersion ) ? latestVersion : null ;
499548}
500549
0 commit comments