@@ -359,9 +359,39 @@ private protected async Task<TestLspServer> CreateXmlTestLspServerAsync(
359
359
return await TestLspServer . CreateAsync ( workspace , lspOptions , TestOutputLspLogger ) ;
360
360
}
361
361
362
+ private void CheckForCompositionErrors ( TestComposition composition )
363
+ {
364
+ // The test compositions tend to have a bunch of errors.
365
+ // We only want to fail the test if we're seeing errors in relevant parts to the language server.
366
+ // This isn't foolproof, but helps catch issues early.
367
+
368
+ var config = composition . GetCompositionConfiguration ( ) ;
369
+ var hasLanguageServerErrors = config . CompositionErrors . Flatten ( ) . Any ( error => error . Parts . Any ( IsRelevantPartError ) ) ;
370
+
371
+ if ( hasLanguageServerErrors )
372
+ {
373
+ try
374
+ {
375
+ config . ThrowOnErrors ( ) ;
376
+ }
377
+ catch ( CompositionFailedException ex )
378
+ {
379
+ // The ToString for the composition failed exception doesn't output a nice set of errors by default, so log it separately
380
+ this . TestOutputLspLogger . LogError ( $ "Encountered errors in the MEF composition: { ex . Message } { Environment . NewLine } { ex . ErrorsAsString } ") ;
381
+ throw ;
382
+ }
383
+ }
384
+
385
+ bool IsRelevantPartError ( ComposedPart part )
386
+ {
387
+ return part . Definition . Type . FullName ? . Contains ( "Microsoft.CodeAnalysis.LanguageServer" ) == true ;
388
+ }
389
+ }
390
+
362
391
internal async Task < LspTestWorkspace > CreateWorkspaceAsync (
363
392
InitializationOptions ? options , string ? workspaceKind , bool mutatingLspWorkspace , TestComposition ? composition = null )
364
393
{
394
+ CheckForCompositionErrors ( composition ?? Composition ) ;
365
395
var workspace = new LspTestWorkspace (
366
396
composition ? . ExportProviderFactory . CreateExportProvider ( ) ?? await CreateExportProviderAsync ( ) ,
367
397
workspaceKind ,
@@ -494,7 +524,8 @@ private protected static LSP.Location GetLocationPlusOne(LSP.Location originalLo
494
524
495
525
private static LSP . DidChangeTextDocumentParams CreateDidChangeTextDocumentParams (
496
526
DocumentUri documentUri ,
497
- ImmutableArray < ( LSP . Range Range , string Text ) > changes )
527
+ ImmutableArray < ( LSP . Range Range , string Text ) > changes ,
528
+ int version = 0 )
498
529
{
499
530
var changeEvents = changes . Select ( change => new LSP . TextDocumentContentChangeEvent
500
531
{
@@ -506,20 +537,22 @@ private static LSP.DidChangeTextDocumentParams CreateDidChangeTextDocumentParams
506
537
{
507
538
TextDocument = new LSP . VersionedTextDocumentIdentifier
508
539
{
509
- DocumentUri = documentUri
540
+ DocumentUri = documentUri ,
541
+ Version = version
510
542
} ,
511
543
ContentChanges = changeEvents
512
544
} ;
513
545
}
514
546
515
- private static LSP . DidOpenTextDocumentParams CreateDidOpenTextDocumentParams ( DocumentUri uri , string source , string languageId = "" )
547
+ private static LSP . DidOpenTextDocumentParams CreateDidOpenTextDocumentParams ( DocumentUri uri , string source , string languageId = "" , int version = 0 )
516
548
=> new LSP . DidOpenTextDocumentParams
517
549
{
518
550
TextDocument = new LSP . TextDocumentItem
519
551
{
520
552
Text = source ,
521
553
DocumentUri = uri ,
522
- LanguageId = languageId
554
+ LanguageId = languageId ,
555
+ Version = version
523
556
}
524
557
} ;
525
558
@@ -704,7 +737,7 @@ public Task ExecutePreSerializedRequestAsync(string methodName, JsonDocument ser
704
737
return _clientRpc . InvokeWithParameterObjectAsync ( methodName , serializedRequest ) ;
705
738
}
706
739
707
- public async Task OpenDocumentAsync ( DocumentUri documentUri , string ? text = null , string languageId = "" )
740
+ public async Task OpenDocumentAsync ( DocumentUri documentUri , string ? text = null , string languageId = "" , int version = 0 )
708
741
{
709
742
if ( text == null )
710
743
{
@@ -714,13 +747,13 @@ public async Task OpenDocumentAsync(DocumentUri documentUri, string? text = null
714
747
text = sourceText . ToString ( ) ;
715
748
}
716
749
717
- var didOpenParams = CreateDidOpenTextDocumentParams ( documentUri , text . ToString ( ) , languageId ) ;
750
+ var didOpenParams = CreateDidOpenTextDocumentParams ( documentUri , text . ToString ( ) , languageId , version ) ;
718
751
await ExecuteRequestAsync < LSP . DidOpenTextDocumentParams , object > ( LSP . Methods . TextDocumentDidOpenName , didOpenParams , CancellationToken . None ) ;
719
752
}
720
753
721
754
/// <summary>
722
755
/// Opens a document in the workspace only, and waits for workspace operations.
723
- /// Use <see cref="OpenDocumentAsync(DocumentUri, string, string)"/> if the document should be opened in LSP"/>
756
+ /// Use <see cref="OpenDocumentAsync(DocumentUri, string, string, int )"/> if the document should be opened in LSP"/>
724
757
/// </summary>
725
758
public async Task OpenDocumentInWorkspaceAsync ( DocumentId documentId , bool openAllLinkedDocuments , SourceText ? text = null )
726
759
{
@@ -745,23 +778,34 @@ public async Task OpenDocumentInWorkspaceAsync(DocumentId documentId, bool openA
745
778
await WaitForWorkspaceOperationsAsync ( TestWorkspace ) ;
746
779
}
747
780
748
- public Task ReplaceTextAsync ( DocumentUri documentUri , params ( LSP . Range Range , string Text ) [ ] changes )
781
+ public Task ReplaceTextAsync ( DocumentUri documentUri , int version , params ( LSP . Range Range , string Text ) [ ] changes )
749
782
{
750
783
var didChangeParams = CreateDidChangeTextDocumentParams (
751
784
documentUri ,
752
- [ .. changes ] ) ;
785
+ [ .. changes ] ,
786
+ version ) ;
753
787
return ExecuteRequestAsync < LSP . DidChangeTextDocumentParams , object > ( LSP . Methods . TextDocumentDidChangeName , didChangeParams , CancellationToken . None ) ;
754
788
}
755
789
756
- public Task InsertTextAsync ( DocumentUri documentUri , params ( int Line , int Column , string Text ) [ ] changes )
790
+ public Task ReplaceTextAsync ( DocumentUri documentUri , params ( LSP . Range Range , string Text ) [ ] changes )
757
791
{
758
- return ReplaceTextAsync ( documentUri , [ .. changes . Select ( change => ( new LSP . Range
792
+ return ReplaceTextAsync ( documentUri , version : 0 , changes ) ;
793
+ }
794
+
795
+ public Task InsertTextAsync ( DocumentUri documentUri , int version , params ( int Line , int Column , string Text ) [ ] changes )
796
+ {
797
+ return ReplaceTextAsync ( documentUri , version , [ .. changes . Select ( change => ( new LSP . Range
759
798
{
760
799
Start = new LSP . Position { Line = change . Line , Character = change . Column } ,
761
800
End = new LSP . Position { Line = change . Line , Character = change . Column }
762
801
} , change . Text ) ) ] ) ;
763
802
}
764
803
804
+ public Task InsertTextAsync ( DocumentUri documentUri , params ( int Line , int Column , string Text ) [ ] changes )
805
+ {
806
+ return InsertTextAsync ( documentUri , version : 0 , changes ) ;
807
+ }
808
+
765
809
public Task DeleteTextAsync ( DocumentUri documentUri , params ( int StartLine , int StartColumn , int EndLine , int EndColumn ) [ ] changes )
766
810
{
767
811
return ReplaceTextAsync ( documentUri , [ .. changes . Select ( change => ( new LSP . Range
0 commit comments