@@ -359,9 +359,35 @@ private protected async Task<TestLspServer> CreateXmlTestLspServerAsync(
359359 return await TestLspServer . CreateAsync ( workspace , lspOptions , TestOutputLspLogger ) ;
360360 }
361361
362+ private void CheckForCompositionErrors ( TestComposition composition )
363+ {
364+ var config = composition . GetCompositionConfiguration ( ) ;
365+ var hasLanguageServerErrors = config . CompositionErrors . Flatten ( ) . Any ( error => error . Parts . Any ( IsRelevantPartError ) ) ;
366+
367+ if ( hasLanguageServerErrors )
368+ {
369+ try
370+ {
371+ config . ThrowOnErrors ( ) ;
372+ }
373+ catch ( CompositionFailedException ex )
374+ {
375+ // The ToString for the composition failed exception doesn't output a nice set of errors by default, so log it separately
376+ this . TestOutputLspLogger . LogError ( $ "Encountered errors in the MEF composition: { ex . Message } { Environment . NewLine } { ex . ErrorsAsString } ") ;
377+ throw ;
378+ }
379+ }
380+
381+ bool IsRelevantPartError ( ComposedPart part )
382+ {
383+ return part . Definition . Type . FullName ? . Contains ( "Microsoft.CodeAnalysis" ) == true && part . Definition . Type . FullName ? . Contains ( "Microsoft.CodeAnalysis.ExternalAccess" ) == false ;
384+ }
385+ }
386+
362387 internal async Task < LspTestWorkspace > CreateWorkspaceAsync (
363388 InitializationOptions ? options , string ? workspaceKind , bool mutatingLspWorkspace , TestComposition ? composition = null )
364389 {
390+ CheckForCompositionErrors ( composition ?? Composition ) ;
365391 var workspace = new LspTestWorkspace (
366392 composition ? . ExportProviderFactory . CreateExportProvider ( ) ?? await CreateExportProviderAsync ( ) ,
367393 workspaceKind ,
@@ -494,7 +520,8 @@ private protected static LSP.Location GetLocationPlusOne(LSP.Location originalLo
494520
495521 private static LSP . DidChangeTextDocumentParams CreateDidChangeTextDocumentParams (
496522 DocumentUri documentUri ,
497- ImmutableArray < ( LSP . Range Range , string Text ) > changes )
523+ ImmutableArray < ( LSP . Range Range , string Text ) > changes ,
524+ int version = 0 )
498525 {
499526 var changeEvents = changes . Select ( change => new LSP . TextDocumentContentChangeEvent
500527 {
@@ -506,20 +533,22 @@ private static LSP.DidChangeTextDocumentParams CreateDidChangeTextDocumentParams
506533 {
507534 TextDocument = new LSP . VersionedTextDocumentIdentifier
508535 {
509- DocumentUri = documentUri
536+ DocumentUri = documentUri ,
537+ Version = version
510538 } ,
511539 ContentChanges = changeEvents
512540 } ;
513541 }
514542
515- private static LSP . DidOpenTextDocumentParams CreateDidOpenTextDocumentParams ( DocumentUri uri , string source , string languageId = "" )
543+ private static LSP . DidOpenTextDocumentParams CreateDidOpenTextDocumentParams ( DocumentUri uri , string source , string languageId = "" , int version = 0 )
516544 => new LSP . DidOpenTextDocumentParams
517545 {
518546 TextDocument = new LSP . TextDocumentItem
519547 {
520548 Text = source ,
521549 DocumentUri = uri ,
522- LanguageId = languageId
550+ LanguageId = languageId ,
551+ Version = version
523552 }
524553 } ;
525554
@@ -704,7 +733,7 @@ public Task ExecutePreSerializedRequestAsync(string methodName, JsonDocument ser
704733 return _clientRpc . InvokeWithParameterObjectAsync ( methodName , serializedRequest ) ;
705734 }
706735
707- public async Task OpenDocumentAsync ( DocumentUri documentUri , string ? text = null , string languageId = "" )
736+ public async Task OpenDocumentAsync ( DocumentUri documentUri , string ? text = null , string languageId = "" , int version = 0 )
708737 {
709738 if ( text == null )
710739 {
@@ -714,13 +743,13 @@ public async Task OpenDocumentAsync(DocumentUri documentUri, string? text = null
714743 text = sourceText . ToString ( ) ;
715744 }
716745
717- var didOpenParams = CreateDidOpenTextDocumentParams ( documentUri , text . ToString ( ) , languageId ) ;
746+ var didOpenParams = CreateDidOpenTextDocumentParams ( documentUri , text . ToString ( ) , languageId , version ) ;
718747 await ExecuteRequestAsync < LSP . DidOpenTextDocumentParams , object > ( LSP . Methods . TextDocumentDidOpenName , didOpenParams , CancellationToken . None ) ;
719748 }
720749
721750 /// <summary>
722751 /// 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"/>
752+ /// Use <see cref="OpenDocumentAsync(DocumentUri, string, string, int )"/> if the document should be opened in LSP"/>
724753 /// </summary>
725754 public async Task OpenDocumentInWorkspaceAsync ( DocumentId documentId , bool openAllLinkedDocuments , SourceText ? text = null )
726755 {
@@ -745,23 +774,34 @@ public async Task OpenDocumentInWorkspaceAsync(DocumentId documentId, bool openA
745774 await WaitForWorkspaceOperationsAsync ( TestWorkspace ) ;
746775 }
747776
748- public Task ReplaceTextAsync ( DocumentUri documentUri , params ( LSP . Range Range , string Text ) [ ] changes )
777+ public Task ReplaceTextAsync ( DocumentUri documentUri , int version , params ( LSP . Range Range , string Text ) [ ] changes )
749778 {
750779 var didChangeParams = CreateDidChangeTextDocumentParams (
751780 documentUri ,
752- [ .. changes ] ) ;
781+ [ .. changes ] ,
782+ version ) ;
753783 return ExecuteRequestAsync < LSP . DidChangeTextDocumentParams , object > ( LSP . Methods . TextDocumentDidChangeName , didChangeParams , CancellationToken . None ) ;
754784 }
755785
756- public Task InsertTextAsync ( DocumentUri documentUri , params ( int Line , int Column , string Text ) [ ] changes )
786+ public Task ReplaceTextAsync ( DocumentUri documentUri , params ( LSP . Range Range , string Text ) [ ] changes )
757787 {
758- return ReplaceTextAsync ( documentUri , [ .. changes . Select ( change => ( new LSP . Range
788+ return ReplaceTextAsync ( documentUri , version : 0 , changes ) ;
789+ }
790+
791+ public Task InsertTextAsync ( DocumentUri documentUri , int version , params ( int Line , int Column , string Text ) [ ] changes )
792+ {
793+ return ReplaceTextAsync ( documentUri , version , [ .. changes . Select ( change => ( new LSP . Range
759794 {
760795 Start = new LSP . Position { Line = change . Line , Character = change . Column } ,
761796 End = new LSP . Position { Line = change . Line , Character = change . Column }
762797 } , change . Text ) ) ] ) ;
763798 }
764799
800+ public Task InsertTextAsync ( DocumentUri documentUri , params ( int Line , int Column , string Text ) [ ] changes )
801+ {
802+ return InsertTextAsync ( documentUri , version : 0 , changes ) ;
803+ }
804+
765805 public Task DeleteTextAsync ( DocumentUri documentUri , params ( int StartLine , int StartColumn , int EndLine , int EndColumn ) [ ] changes )
766806 {
767807 return ReplaceTextAsync ( documentUri , [ .. changes . Select ( change => ( new LSP . Range
0 commit comments