@@ -39,7 +39,7 @@ import { GoWorkspaceSymbolProvider } from './goSymbol';
39
39
import { getTool , Tool } from './goTools' ;
40
40
import { GoTypeDefinitionProvider } from './goTypeDefinition' ;
41
41
import { getFromGlobalState , updateGlobalState } from './stateUtils' ;
42
- import { getBinPath , getCurrentGoPath , getGoConfig } from './util' ;
42
+ import { getBinPath , getCurrentGoPath , getGoConfig , getGoVersion } from './util' ;
43
43
44
44
interface LanguageServerConfig {
45
45
serverName : string ;
@@ -84,22 +84,43 @@ export async function startLanguageServerWithFallback(ctx: vscode.ExtensionConte
84
84
if ( activation && cfg . enabled && cfg . serverName === 'gopls' ) {
85
85
const tool = getTool ( cfg . serverName ) ;
86
86
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 ;
98
119
}
99
120
}
100
121
}
101
122
102
- const started = await startLanguageServer ( ctx , cfg ) ;
123
+ const started = await startLanguageServer ( ctx , cfg , usingGo2Go ) ;
103
124
104
125
// If the server has been disabled, or failed to start,
105
126
// fall back to the default providers, while making sure not to
@@ -109,7 +130,8 @@ export async function startLanguageServerWithFallback(ctx: vscode.ExtensionConte
109
130
}
110
131
}
111
132
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 > {
113
135
// If the client has already been started, make sure to clear existing
114
136
// diagnostics and stop it.
115
137
if ( languageClient ) {
@@ -128,7 +150,7 @@ async function startLanguageServer(ctx: vscode.ExtensionContext, config: Languag
128
150
// Track the latest config used to start the language server,
129
151
// and rebuild the language client.
130
152
latestConfig = config ;
131
- languageClient = await buildLanguageClient ( config ) ;
153
+ languageClient = await buildLanguageClient ( config , usingGo2Go ) ;
132
154
}
133
155
134
156
// If the user has not enabled the language server, return early.
@@ -158,7 +180,7 @@ async function startLanguageServer(ctx: vscode.ExtensionContext, config: Languag
158
180
return true ;
159
181
}
160
182
161
- async function buildLanguageClient ( config : LanguageServerConfig ) : Promise < LanguageClient > {
183
+ async function buildLanguageClient ( config : LanguageServerConfig , usingGo2Go : boolean ) : Promise < LanguageClient > {
162
184
// Reuse the same output channel for each instance of the server.
163
185
if ( config . enabled && ! serverOutputChannel ) {
164
186
serverOutputChannel = vscode . window . createOutputChannel ( config . serverName ) ;
@@ -173,12 +195,39 @@ async function buildLanguageClient(config: LanguageServerConfig): Promise<Langua
173
195
} ,
174
196
{
175
197
initializationOptions : { } ,
176
- documentSelector : [ 'go' , 'go.mod' , 'go.sum' ] ,
198
+ documentSelector : [ 'go' , 'go2' , ' go.mod', 'go.sum' ] ,
177
199
uriConverters : {
178
200
// 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
+ } ,
182
231
} ,
183
232
outputChannel : serverOutputChannel ,
184
233
revealOutputChannelOn : RevealOutputChannelOn . Never ,
@@ -494,7 +543,7 @@ export async function shouldUpdateLanguageServer(
494
543
495
544
// If the user's version does not contain a timestamp,
496
545
// 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 } ) ;
498
547
return semver . lt ( usersVersionSemver , latestVersion ) ? latestVersion : null ;
499
548
}
500
549
0 commit comments