@@ -47,6 +47,7 @@ type buffer struct {
47
47
version int
48
48
path string
49
49
content []string
50
+ dirty bool
50
51
}
51
52
52
53
func (b buffer ) text () string {
@@ -270,10 +271,28 @@ func (e *Editor) onFileChanges(ctx context.Context, evts []FileEvent) {
270
271
if e .Server == nil {
271
272
return
272
273
}
274
+ e .mu .Lock ()
273
275
var lspevts []protocol.FileEvent
274
276
for _ , evt := range evts {
277
+ // Always send an on-disk change, even for events that seem useless
278
+ // because they're shadowed by an open buffer.
275
279
lspevts = append (lspevts , evt .ProtocolEvent )
280
+
281
+ if buf , ok := e .buffers [evt .Path ]; ok {
282
+ // Following VS Code, don't honor deletions or changes to dirty buffers.
283
+ if buf .dirty || evt .ProtocolEvent .Type == protocol .Deleted {
284
+ continue
285
+ }
286
+
287
+ content , err := e .sandbox .Workdir .ReadFile (evt .Path )
288
+ if err != nil {
289
+ continue // A race with some other operation.
290
+ }
291
+ // During shutdown, this call will fail. Ignore the error.
292
+ _ = e .setBufferContentLocked (ctx , evt .Path , false , strings .Split (content , "\n " ), nil )
293
+ }
276
294
}
295
+ e .mu .Unlock ()
277
296
e .Server .DidChangeWatchedFiles (ctx , & protocol.DidChangeWatchedFilesParams {
278
297
Changes : lspevts ,
279
298
})
@@ -285,15 +304,7 @@ func (e *Editor) OpenFile(ctx context.Context, path string) error {
285
304
if err != nil {
286
305
return err
287
306
}
288
- return e .CreateBuffer (ctx , path , content )
289
- }
290
-
291
- func newBuffer (path , content string ) buffer {
292
- return buffer {
293
- version : 1 ,
294
- path : path ,
295
- content : strings .Split (content , "\n " ),
296
- }
307
+ return e .createBuffer (ctx , path , false , content )
297
308
}
298
309
299
310
func textDocumentItem (wd * Workdir , buf buffer ) protocol.TextDocumentItem {
@@ -314,7 +325,16 @@ func textDocumentItem(wd *Workdir, buf buffer) protocol.TextDocumentItem {
314
325
// CreateBuffer creates a new unsaved buffer corresponding to the workdir path,
315
326
// containing the given textual content.
316
327
func (e * Editor ) CreateBuffer (ctx context.Context , path , content string ) error {
317
- buf := newBuffer (path , content )
328
+ return e .createBuffer (ctx , path , true , content )
329
+ }
330
+
331
+ func (e * Editor ) createBuffer (ctx context.Context , path string , dirty bool , content string ) error {
332
+ buf := buffer {
333
+ version : 1 ,
334
+ path : path ,
335
+ content : strings .Split (content , "\n " ),
336
+ dirty : dirty ,
337
+ }
318
338
e .mu .Lock ()
319
339
e .buffers [path ] = buf
320
340
item := textDocumentItem (e .sandbox .Workdir , buf )
@@ -396,6 +416,12 @@ func (e *Editor) SaveBufferWithoutActions(ctx context.Context, path string) erro
396
416
if err := e .sandbox .Workdir .WriteFile (ctx , path , content ); err != nil {
397
417
return errors .Errorf ("writing %q: %w" , path , err )
398
418
}
419
+
420
+ e .mu .Lock ()
421
+ buf .dirty = false
422
+ e .buffers [path ] = buf
423
+ e .mu .Unlock ()
424
+
399
425
if e .Server != nil {
400
426
params := & protocol.DidSaveTextDocumentParams {
401
427
TextDocument : protocol.VersionedTextDocumentIdentifier {
@@ -534,7 +560,7 @@ func (e *Editor) SetBufferContent(ctx context.Context, path, content string) err
534
560
e .mu .Lock ()
535
561
defer e .mu .Unlock ()
536
562
lines := strings .Split (content , "\n " )
537
- return e .setBufferContentLocked (ctx , path , lines , nil )
563
+ return e .setBufferContentLocked (ctx , path , true , lines , nil )
538
564
}
539
565
540
566
// BufferText returns the content of the buffer with the given name.
@@ -563,16 +589,17 @@ func (e *Editor) editBufferLocked(ctx context.Context, path string, edits []Edit
563
589
if err != nil {
564
590
return err
565
591
}
566
- return e .setBufferContentLocked (ctx , path , content , edits )
592
+ return e .setBufferContentLocked (ctx , path , true , content , edits )
567
593
}
568
594
569
- func (e * Editor ) setBufferContentLocked (ctx context.Context , path string , content []string , fromEdits []Edit ) error {
595
+ func (e * Editor ) setBufferContentLocked (ctx context.Context , path string , dirty bool , content []string , fromEdits []Edit ) error {
570
596
buf , ok := e .buffers [path ]
571
597
if ! ok {
572
598
return fmt .Errorf ("unknown buffer %q" , path )
573
599
}
574
600
buf .content = content
575
601
buf .version ++
602
+ buf .dirty = dirty
576
603
e .buffers [path ] = buf
577
604
// A simple heuristic: if there is only one edit, send it incrementally.
578
605
// Otherwise, send the entire content.
@@ -739,7 +766,16 @@ func (e *Editor) ExecuteCommand(ctx context.Context, params *protocol.ExecuteCom
739
766
if ! match {
740
767
return nil , fmt .Errorf ("unsupported command %q" , params .Command )
741
768
}
742
- return e .Server .ExecuteCommand (ctx , params )
769
+ result , err := e .Server .ExecuteCommand (ctx , params )
770
+ if err != nil {
771
+ return nil , err
772
+ }
773
+ // Some commands use the go command, which writes directly to disk.
774
+ // For convenience, check for those changes.
775
+ if err := e .sandbox .Workdir .CheckForFileChanges (ctx ); err != nil {
776
+ return nil , err
777
+ }
778
+ return result , nil
743
779
}
744
780
745
781
func convertEdits (protocolEdits []protocol.TextEdit ) []Edit {
0 commit comments