Example #1
0
        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);
        }
Example #8
0
        // 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);
            }
        }