@@ -1335,41 +1335,51 @@ func rename(env *Env, loc protocol.Location, newName string) (map[string][]byte,
1335
1335
return nil , err
1336
1336
}
1337
1337
1338
- return applyDocumentChanges (env , editMap .DocumentChanges )
1338
+ fileChanges := make (map [string ][]byte )
1339
+ if err := applyDocumentChanges (env , editMap .DocumentChanges , fileChanges ); err != nil {
1340
+ return nil , fmt .Errorf ("applying document changes: %v" , err )
1341
+ }
1342
+ return fileChanges , nil
1339
1343
}
1340
1344
1341
- // applyDocumentChanges returns the effect of applying the document
1342
- // changes to the contents of the Editor buffers. The actual editor
1343
- // buffers are unchanged.
1344
- func applyDocumentChanges (env * Env , changes []protocol.DocumentChanges ) (map [string ][]byte , error ) {
1345
- result := make (map [string ][]byte )
1345
+ // applyDocumentChanges applies the given document changes to the editor buffer
1346
+ // content, recording the resulting contents in the fileChanges map. It is an
1347
+ // error for a change to an edit a file that is already present in the
1348
+ // fileChanges map.
1349
+ func applyDocumentChanges (env * Env , changes []protocol.DocumentChanges , fileChanges map [string ][]byte ) error {
1350
+ getMapper := func (path string ) (* protocol.Mapper , error ) {
1351
+ if _ , ok := fileChanges [path ]; ok {
1352
+ return nil , fmt .Errorf ("internal error: %s is already edited" , path )
1353
+ }
1354
+ return env .Editor .Mapper (path )
1355
+ }
1356
+
1346
1357
for _ , change := range changes {
1347
1358
if change .RenameFile != nil {
1348
1359
// rename
1349
1360
oldFile := env .Sandbox .Workdir .URIToPath (change .RenameFile .OldURI )
1350
- newFile := env .Sandbox .Workdir .URIToPath (change .RenameFile .NewURI )
1351
- mapper , err := env .Editor .Mapper (oldFile )
1361
+ mapper , err := getMapper (oldFile )
1352
1362
if err != nil {
1353
- return nil , err
1363
+ return err
1354
1364
}
1355
- result [ newFile ] = mapper . Content
1356
-
1365
+ newFile := env . Sandbox . Workdir . URIToPath ( change . RenameFile . NewURI )
1366
+ fileChanges [ newFile ] = mapper . Content
1357
1367
} else {
1358
1368
// edit
1359
1369
filename := env .Sandbox .Workdir .URIToPath (change .TextDocumentEdit .TextDocument .URI )
1360
- mapper , err := env . Editor . Mapper (filename )
1370
+ mapper , err := getMapper (filename )
1361
1371
if err != nil {
1362
- return nil , err
1372
+ return err
1363
1373
}
1364
1374
patched , _ , err := source .ApplyProtocolEdits (mapper , change .TextDocumentEdit .Edits )
1365
1375
if err != nil {
1366
- return nil , err
1376
+ return err
1367
1377
}
1368
- result [filename ] = patched
1378
+ fileChanges [filename ] = patched
1369
1379
}
1370
1380
}
1371
1381
1372
- return result , nil
1382
+ return nil
1373
1383
}
1374
1384
1375
1385
func codeActionMarker (mark marker , actionKind string , start , end protocol.Location , golden * Golden ) {
@@ -1453,40 +1463,56 @@ func codeAction(env *Env, uri protocol.DocumentURI, rng protocol.Range, actionKi
1453
1463
}
1454
1464
action := candidates [0 ]
1455
1465
1466
+ // Apply the codeAction.
1467
+ //
1468
+ // Spec:
1469
+ // "If a code action provides an edit and a command, first the edit is
1470
+ // executed and then the command."
1471
+ fileChanges := make (map [string ][]byte )
1456
1472
// An action may specify an edit and/or a command, to be
1457
1473
// applied in that order. But since applyDocumentChanges(env,
1458
1474
// action.Edit.DocumentChanges) doesn't compose, for now we
1459
1475
// assert that all commands used in the @suggestedfix tests
1460
1476
// return only a command.
1461
- if action .Edit != nil && action .Edit .DocumentChanges != nil {
1462
- env .T .Errorf ("internal error: discarding unexpected CodeAction{Kind=%s, Title=%q}.Edit.DocumentChanges" , action .Kind , action .Title )
1463
- }
1464
- if action .Command == nil {
1465
- return nil , fmt .Errorf ("missing CodeAction{Kind=%s, Title=%q}.Command" , action .Kind , action .Title )
1477
+ if action .Edit != nil {
1478
+ if action .Edit .Changes != nil {
1479
+ env .T .Errorf ("internal error: discarding unexpected CodeAction{Kind=%s, Title=%q}.Edit.Changes" , action .Kind , action .Title )
1480
+ }
1481
+ if action .Edit .DocumentChanges != nil {
1482
+ if err := applyDocumentChanges (env , action .Edit .DocumentChanges , fileChanges ); err != nil {
1483
+ return nil , fmt .Errorf ("applying document changes: %v" , err )
1484
+ }
1485
+ }
1466
1486
}
1467
1487
1468
- // This is a typical CodeAction command:
1469
- //
1470
- // Title: "Implement error"
1471
- // Command: gopls.apply_fix
1472
- // Arguments: [{"Fix":"stub_methods","URI":".../a.go","Range":...}}]
1473
- //
1474
- // The client makes an ExecuteCommand RPC to the server,
1475
- // which dispatches it to the ApplyFix handler.
1476
- // ApplyFix dispatches to the "stub_methods" suggestedfix hook (the meat).
1477
- // The server then makes an ApplyEdit RPC to the client,
1478
- // whose Awaiter hook gathers the edits instead of applying them.
1479
-
1480
- _ = env .Awaiter .takeDocumentChanges () // reset (assuming Env is confined to this thread)
1488
+ if action .Command != nil {
1489
+ // This is a typical CodeAction command:
1490
+ //
1491
+ // Title: "Implement error"
1492
+ // Command: gopls.apply_fix
1493
+ // Arguments: [{"Fix":"stub_methods","URI":".../a.go","Range":...}}]
1494
+ //
1495
+ // The client makes an ExecuteCommand RPC to the server,
1496
+ // which dispatches it to the ApplyFix handler.
1497
+ // ApplyFix dispatches to the "stub_methods" suggestedfix hook (the meat).
1498
+ // The server then makes an ApplyEdit RPC to the client,
1499
+ // whose Awaiter hook gathers the edits instead of applying them.
1500
+
1501
+ _ = env .Awaiter .takeDocumentChanges () // reset (assuming Env is confined to this thread)
1502
+
1503
+ if _ , err := env .Editor .Server .ExecuteCommand (env .Ctx , & protocol.ExecuteCommandParams {
1504
+ Command : action .Command .Command ,
1505
+ Arguments : action .Command .Arguments ,
1506
+ }); err != nil {
1507
+ env .T .Fatalf ("error converting command %q to edits: %v" , action .Command .Command , err )
1508
+ }
1481
1509
1482
- if _ , err := env .Editor .Server .ExecuteCommand (env .Ctx , & protocol.ExecuteCommandParams {
1483
- Command : action .Command .Command ,
1484
- Arguments : action .Command .Arguments ,
1485
- }); err != nil {
1486
- env .T .Fatalf ("error converting command %q to edits: %v" , action .Command .Command , err )
1510
+ if err := applyDocumentChanges (env , env .Awaiter .takeDocumentChanges (), fileChanges ); err != nil {
1511
+ return nil , fmt .Errorf ("applying document changes from command: %v" , err )
1512
+ }
1487
1513
}
1488
1514
1489
- return applyDocumentChanges ( env , env . Awaiter . takeDocumentChanges ())
1515
+ return fileChanges , nil
1490
1516
}
1491
1517
1492
1518
// TODO(adonovan): suggestedfixerr
0 commit comments