@@ -54,7 +54,7 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...interf
54
54
for _ , scope := range scopes {
55
55
switch scope := scope .(type ) {
56
56
case packagePath :
57
- if scope == "command-line-arguments" {
57
+ if isCommandLineArguments ( string ( scope )) {
58
58
panic ("attempted to load command-line-arguments" )
59
59
}
60
60
// The only time we pass package paths is when we're doing a
@@ -204,12 +204,6 @@ func (s *snapshot) parseLoadError(ctx context.Context, loadErr error) *source.Cr
204
204
// workspaceLayoutErrors returns a diagnostic for every open file, as well as
205
205
// an error message if there are no open files.
206
206
func (s * snapshot ) WorkspaceLayoutError (ctx context.Context ) * source.CriticalError {
207
- // Assume the workspace is misconfigured only if we've detected an invalid
208
- // build configuration. Currently, a valid build configuration is either a
209
- // module at the root of the view or a GOPATH workspace.
210
- if s .ValidBuildConfiguration () {
211
- return nil
212
- }
213
207
if len (s .workspace .getKnownModFiles ()) == 0 {
214
208
return nil
215
209
}
@@ -219,33 +213,70 @@ func (s *snapshot) WorkspaceLayoutError(ctx context.Context) *source.CriticalErr
219
213
if s .workspace .moduleSource != legacyWorkspace {
220
214
return nil
221
215
}
222
- // The user's workspace contains go.mod files and they have
223
- // GO111MODULE=on, so we should guide them to create a
224
- // workspace folder for each module.
225
-
226
- // Add a diagnostic to every open file, or return a general error if
227
- // there aren't any.
228
- var open []source.VersionedFileHandle
229
- s .mu .Lock ()
230
- for _ , fh := range s .files {
231
- if s .isOpenLocked (fh .URI ()) {
232
- open = append (open , fh )
233
- }
216
+ // If the user has one module per view, there is nothing to warn about.
217
+ if s .ValidBuildConfiguration () && len (s .workspace .getKnownModFiles ()) == 1 {
218
+ return nil
234
219
}
235
- s .mu .Unlock ()
236
220
237
- msg := `gopls requires one module per workspace folder.
221
+ // Apply diagnostics about the workspace configuration to relevant open
222
+ // files.
223
+ openFiles := s .openFiles ()
224
+
225
+ // If the snapshot does not have a valid build configuration, it may be
226
+ // that the user has opened a directory that contains multiple modules.
227
+ // Check for that an warn about it.
228
+ if ! s .ValidBuildConfiguration () {
229
+ msg := `gopls requires a module at the root of your workspace.
238
230
You can work with multiple modules by opening each one as a workspace folder.
239
231
Improvements to this workflow will be coming soon (https://github.com/golang/go/issues/32394),
240
232
and you can learn more here: https://github.com/golang/go/issues/36899.`
241
-
242
- criticalError := & source.CriticalError {
243
- MainError : errors .New (msg ),
233
+ return & source.CriticalError {
234
+ MainError : errors .Errorf (msg ),
235
+ ErrorList : s .applyCriticalErrorToFiles (ctx , msg , openFiles ),
236
+ }
244
237
}
245
- if len (open ) == 0 {
246
- return criticalError
238
+
239
+ // If the user has one active go.mod file, they may still be editing files
240
+ // in nested modules. Check the module of each open file and add warnings
241
+ // that the nested module must be opened as a workspace folder.
242
+ if len (s .workspace .getActiveModFiles ()) == 1 {
243
+ // Get the active root go.mod file to compare against.
244
+ var rootModURI span.URI
245
+ for uri := range s .workspace .getActiveModFiles () {
246
+ rootModURI = uri
247
+ }
248
+ nestedModules := map [span.URI ][]source.VersionedFileHandle {}
249
+ for _ , fh := range openFiles {
250
+ modURI := moduleForURI (s .workspace .knownModFiles , fh .URI ())
251
+ if modURI != rootModURI {
252
+ nestedModules [modURI ] = append (nestedModules [modURI ], fh )
253
+ }
254
+ }
255
+ // Add a diagnostic to each file in a nested module to mark it as
256
+ // "orphaned". Don't show a general diagnostic in the progress bar,
257
+ // because the user may still want to edit a file in a nested module.
258
+ var srcErrs []* source.Error
259
+ for modURI , uris := range nestedModules {
260
+ msg := fmt .Sprintf (`This file is in %s, which is a nested module in the %s module.
261
+ gopls currently requires one module per workspace folder.
262
+ Please open %s as a separate workspace folder.
263
+ You can learn more here: https://github.com/golang/go/issues/36899.
264
+ ` , modURI .Filename (), rootModURI .Filename (), modURI .Filename ())
265
+ srcErrs = append (srcErrs , s .applyCriticalErrorToFiles (ctx , msg , uris )... )
266
+ }
267
+ if len (srcErrs ) != 0 {
268
+ return & source.CriticalError {
269
+ MainError : errors .Errorf (`You are working in a nested module. Please open it as a separate workspace folder.` ),
270
+ ErrorList : srcErrs ,
271
+ }
272
+ }
247
273
}
248
- for _ , fh := range open {
274
+ return nil
275
+ }
276
+
277
+ func (s * snapshot ) applyCriticalErrorToFiles (ctx context.Context , msg string , files []source.VersionedFileHandle ) []* source.Error {
278
+ var srcErrs []* source.Error
279
+ for _ , fh := range files {
249
280
// Place the diagnostics on the package or module declarations.
250
281
var rng protocol.Range
251
282
switch fh .Kind () {
@@ -263,14 +294,14 @@ and you can learn more here: https://github.com/golang/go/issues/36899.`
263
294
}
264
295
}
265
296
}
266
- criticalError . ErrorList = append (criticalError . ErrorList , & source.Error {
297
+ srcErrs = append (srcErrs , & source.Error {
267
298
URI : fh .URI (),
268
299
Range : rng ,
269
300
Kind : source .ListError ,
270
301
Message : msg ,
271
302
})
272
303
}
273
- return criticalError
304
+ return srcErrs
274
305
}
275
306
276
307
type workspaceDirKey string
0 commit comments