@@ -275,26 +275,34 @@ func (m *moduleErrorMap) Error() string {
275
275
return buf .String ()
276
276
}
277
277
278
- // workspaceLayoutErrors returns a diagnostic for every open file, as well as
279
- // an error message if there are no open files.
280
- func (s * snapshot ) workspaceLayoutError (ctx context.Context ) * source.CriticalError {
278
+ // workspaceLayoutErrors returns an error decribing a misconfiguration of the
279
+ // workspace, along with related diagnostic.
280
+ //
281
+ // The unusual argument ordering of results is intentional: if the resulting
282
+ // error is nil, so must be the resulting diagnostics.
283
+ //
284
+ // If ctx is cancelled, it may return ctx.Err(), nil.
285
+ //
286
+ // TODO(rfindley): separate workspace diagnostics from critical workspace
287
+ // errors.
288
+ func (s * snapshot ) workspaceLayoutError (ctx context.Context ) (error , []* source.Diagnostic ) {
281
289
// TODO(rfindley): do we really not want to show a critical error if the user
282
290
// has no go.mod files?
283
291
if len (s .workspace .getKnownModFiles ()) == 0 {
284
- return nil
292
+ return nil , nil
285
293
}
286
294
287
295
// TODO(rfindley): both of the checks below should be delegated to the workspace.
288
296
if s .view .effectiveGO111MODULE () == off {
289
- return nil
297
+ return nil , nil
290
298
}
291
299
if s .workspace .moduleSource != legacyWorkspace {
292
- return nil
300
+ return nil , nil
293
301
}
294
302
295
303
// If the user has one module per view, there is nothing to warn about.
296
304
if s .ValidBuildConfiguration () && len (s .workspace .getKnownModFiles ()) == 1 {
297
- return nil
305
+ return nil , nil
298
306
}
299
307
300
308
// Apply diagnostics about the workspace configuration to relevant open
@@ -320,51 +328,57 @@ go workspaces (go.work files).
320
328
See the documentation for more information on setting up your workspace:
321
329
https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.`
322
330
}
323
- return & source.CriticalError {
324
- MainError : fmt .Errorf (msg ),
325
- Diagnostics : s .applyCriticalErrorToFiles (ctx , msg , openFiles ),
326
- }
331
+ return fmt .Errorf (msg ), s .applyCriticalErrorToFiles (ctx , msg , openFiles )
327
332
}
328
333
329
334
// If the user has one active go.mod file, they may still be editing files
330
335
// in nested modules. Check the module of each open file and add warnings
331
336
// that the nested module must be opened as a workspace folder.
332
337
if len (s .workspace .ActiveModFiles ()) == 1 {
333
338
// Get the active root go.mod file to compare against.
334
- var rootModURI span. URI
339
+ var rootMod string
335
340
for uri := range s .workspace .ActiveModFiles () {
336
- rootModURI = uri
341
+ rootMod = uri . Filename ()
337
342
}
338
- nestedModules := map [string ][]source.VersionedFileHandle {}
343
+ rootDir := filepath .Dir (rootMod )
344
+ nestedModules := make (map [string ][]source.VersionedFileHandle )
339
345
for _ , fh := range openFiles {
340
- modURI := moduleForURI (s .workspace .knownModFiles , fh .URI ())
341
- if modURI != rootModURI {
342
- modDir := filepath .Dir (modURI .Filename ())
346
+ mod , err := findRootPattern (ctx , filepath .Dir (fh .URI ().Filename ()), "go.mod" , s )
347
+ if err != nil {
348
+ if ctx .Err () != nil {
349
+ return ctx .Err (), nil
350
+ }
351
+ continue
352
+ }
353
+ if mod == "" {
354
+ continue
355
+ }
356
+ if mod != rootMod && source .InDir (rootDir , mod ) {
357
+ modDir := filepath .Dir (mod )
343
358
nestedModules [modDir ] = append (nestedModules [modDir ], fh )
344
359
}
345
360
}
361
+ var multiModuleMsg string
362
+ if s .view .goversion >= 18 {
363
+ multiModuleMsg = `To work on multiple modules at once, please use a go.work file.
364
+ See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.`
365
+ } else {
366
+ multiModuleMsg = `To work on multiple modules at once, please upgrade to Go 1.18 and use a go.work file.
367
+ See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.`
368
+ }
346
369
// Add a diagnostic to each file in a nested module to mark it as
347
370
// "orphaned". Don't show a general diagnostic in the progress bar,
348
371
// because the user may still want to edit a file in a nested module.
349
372
var srcDiags []* source.Diagnostic
350
373
for modDir , uris := range nestedModules {
351
- msg := fmt .Sprintf (`This file is in %s, which is a nested module in the %s module.
352
- gopls currently requires one module per workspace folder.
353
- Please open %s as a separate workspace folder.
354
- You can learn more here: https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.
355
- ` , modDir , filepath .Dir (rootModURI .Filename ()), modDir )
374
+ msg := fmt .Sprintf ("This file is in %s, which is a nested module in the %s module.\n %s" , modDir , rootMod , multiModuleMsg )
356
375
srcDiags = append (srcDiags , s .applyCriticalErrorToFiles (ctx , msg , uris )... )
357
376
}
358
377
if len (srcDiags ) != 0 {
359
- return & source.CriticalError {
360
- MainError : fmt .Errorf (`You are working in a nested module.
361
- Please open it as a separate workspace folder. Learn more:
362
- https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.` ),
363
- Diagnostics : srcDiags ,
364
- }
378
+ return fmt .Errorf ("You have opened a nested module.\n %s" , multiModuleMsg ), srcDiags
365
379
}
366
380
}
367
- return nil
381
+ return nil , nil
368
382
}
369
383
370
384
func (s * snapshot ) applyCriticalErrorToFiles (ctx context.Context , msg string , files []source.VersionedFileHandle ) []* source.Diagnostic {
0 commit comments