private DefaultLSPDocumentSnapshot UpdateSnapshot() { var virtualDocumentSnapshots = new VirtualDocumentSnapshot[VirtualDocuments.Count]; for (var i = 0; i < VirtualDocuments.Count; i++) { virtualDocumentSnapshots[i] = VirtualDocuments[i].CurrentSnapshot; } return(new DefaultLSPDocumentSnapshot(Uri, TextBuffer.CurrentSnapshot, virtualDocumentSnapshots, Version)); }
public LSPDocumentChangeEventArgs( LSPDocumentSnapshot old, LSPDocumentSnapshot @new, VirtualDocumentSnapshot virtualOld, VirtualDocumentSnapshot virtualNew, LSPDocumentChangeKind kind) { Old = old; New = @new; VirtualOld = virtualOld; VirtualNew = virtualNew; Kind = kind; }
public DocumentSynchronizingContext( VirtualDocumentSnapshot virtualDocument, int expectedHostDocumentVersion, TimeSpan timeout, CancellationToken requestCancellationToken) { VirtualDocument = virtualDocument; ExpectedHostDocumentVersion = expectedHostDocumentVersion; _onSynchronizedSource = new TaskCompletionSource <bool>(); _cts = CancellationTokenSource.CreateLinkedTokenSource(requestCancellationToken); // This cancellation token is the one passed in from the call-site that needs to synchronize an LSP document with a virtual document. // Meaning, if the outer token is cancelled we need to fail to synchronize. _cts.Token.Register(() => SetSynchronized(false)); _cts.CancelAfter(timeout); }
public abstract Task <bool> TrySynchronizeVirtualDocumentAsync(LSPDocumentSnapshot document, VirtualDocumentSnapshot virtualDocument, CancellationToken cancellationToken);
public override Task <bool> TrySynchronizeVirtualDocumentAsync(int requiredHostDocumentVersion, VirtualDocumentSnapshot virtualDocument, CancellationToken cancellationToken) { if (virtualDocument is null) { throw new ArgumentNullException(nameof(virtualDocument)); } lock (DocumentContextLock) { if (!_virtualDocumentContexts.TryGetValue(virtualDocument.Uri, out var documentContext)) { throw new InvalidOperationException("Document context should never be null here."); } if (requiredHostDocumentVersion == documentContext.SeenHostDocumentVersion) { // Already synchronized return(Task.FromResult(true)); } if (requiredHostDocumentVersion != documentContext.SynchronizingContext?.RequiredHostDocumentVersion) { // Currently tracked synchronizing context is not sufficient, need to update a new one. documentContext.UpdateSynchronizingContext(requiredHostDocumentVersion, cancellationToken); } else { // Already have a synchronizing context for this type of request, memoize the results. } var synchronizingContext = documentContext.SynchronizingContext; return(synchronizingContext.OnSynchronizedAsync); } }
public abstract Task <bool> TrySynchronizeVirtualDocumentAsync(int requiredHostDocumentVersion, VirtualDocumentSnapshot virtualDocument, CancellationToken cancellationToken);
public async override Task <bool> TrySynchronizeVirtualDocumentAsync(LSPDocumentSnapshot document, VirtualDocumentSnapshot virtualDocument, CancellationToken cancellationToken) { if (document is null) { throw new ArgumentNullException(nameof(document)); } if (virtualDocument is null) { throw new ArgumentNullException(nameof(virtualDocument)); } if (!document.VirtualDocuments.Contains(virtualDocument)) { throw new InvalidOperationException("Virtual document snapshot must belong to the provided LSP document snapshot."); } if (document.Version == virtualDocument.HostDocumentSyncVersion) { // Already synchronized return(true); } var synchronizingContext = _synchronizingContexts.AddOrUpdate( virtualDocument.Uri, (uri) => new DocumentSynchronizingContext(virtualDocument, document.Version, _synchronizationTimeout, cancellationToken), (uri, existingContext) => { if (virtualDocument == existingContext.VirtualDocument && document.Version == existingContext.ExpectedHostDocumentVersion) { // Already contain a synchronizing context that represents this request and it's in-process of being calculated. return(existingContext); } // Cancel old request existingContext.SetSynchronized(false); return(new DocumentSynchronizingContext(virtualDocument, document.Version, _synchronizationTimeout, cancellationToken)); }); var result = await _joinableTaskFactory.RunAsync(() => synchronizingContext.OnSynchronizedAsync); _synchronizingContexts.TryRemove(virtualDocument.Uri, out _); return(result); }
// Internal for testing public override void Changed(LSPDocumentSnapshot old, LSPDocumentSnapshot @new, VirtualDocumentSnapshot virtualOld, VirtualDocumentSnapshot virtualNew, LSPDocumentChangeKind kind) { // We need the below check to address a race condition between when a request is sent to the C# server // for a generated document and when the C# server receives a document/didOpen notification. This race // condition may occur when the Razor server finishes initializing before C# receives and processes the // document open request. // This workaround adds the Razor client name to the generated document so the C# server will recognize // it, despite the document not being formally opened. Note this is meant to only be a temporary // workaround until a longer-term solution is implemented in the future. if (kind == LSPDocumentChangeKind.Added && _dynamicFileInfoProvider is DefaultRazorDynamicFileInfoProvider defaultProvider) { defaultProvider.PromoteBackgroundDocument(@new.Uri, CSharpDocumentPropertiesService.Instance); } if (kind != LSPDocumentChangeKind.VirtualDocumentChanged) { return; } if (virtualNew is CSharpVirtualDocumentSnapshot) { var csharpContainer = new CSharpVirtualDocumentContainer(_lspDocumentMappingProvider, @new, virtualNew.Snapshot); _dynamicFileInfoProvider.UpdateLSPFileInfo(@new.Uri, csharpContainer); } }