public async Task <Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
        {
            var uri      = notification.TextDocument.Uri.GetAbsoluteOrUNCPath();
            var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                _documentResolver.TryResolveDocument(uri, out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None).ConfigureAwait(false);

            if (document is null)
            {
                throw new InvalidOperationException(RazorLS.Resources.FormatDocument_Not_Found(uri));
            }

            var sourceText = await document.GetTextAsync();

            sourceText = ApplyContentChanges(notification.ContentChanges, sourceText);

            if (notification.TextDocument.Version is null)
            {
                throw new InvalidOperationException(RazorLS.Resources.Version_Should_Not_Be_Null);
            }

            await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                () => _projectService.UpdateDocument(document.FilePath, sourceText, notification.TextDocument.Version.Value),
                CancellationToken.None).ConfigureAwait(false);

            return(Unit.Value);
        }
コード例 #2
0
        public async Task StartAsync(string workspaceDirectory, CancellationToken cancellationToken)
        {
            if (workspaceDirectory is null)
            {
                throw new ArgumentNullException(nameof(workspaceDirectory));
            }

            // Dive through existing project files and fabricate "added" events so listeners can accurately listen to state changes for them.

            workspaceDirectory = _filePathNormalizer.Normalize(workspaceDirectory);
            var existingProjectFiles = GetExistingProjectFiles(workspaceDirectory);

            await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                foreach (var projectFilePath in existingProjectFiles)
                {
                    FileSystemWatcher_ProjectFileEvent(projectFilePath, RazorFileChangeKind.Added);
                }
            }, cancellationToken).ConfigureAwait(false);

            // This is an entry point for testing
            OnInitializationFinished();

            if (cancellationToken.IsCancellationRequested)
            {
                // Client cancelled connection, no need to setup any file watchers. Server is about to tear down.
                return;
            }

            // Start listening for project file changes (added/removed/renamed).

            _watcher = new RazorFileSystemWatcher(workspaceDirectory, ProjectFileExtensionPattern)
            {
                NotifyFilter          = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime,
                IncludeSubdirectories = true,
            };

            _watcher.Created += (sender, args) => FileSystemWatcher_ProjectFileEvent_Background(args.FullPath, RazorFileChangeKind.Added);
            _watcher.Deleted += (sender, args) => FileSystemWatcher_ProjectFileEvent_Background(args.FullPath, RazorFileChangeKind.Removed);
            _watcher.Renamed += (sender, args) =>
            {
                // Translate file renames into remove->add

                if (args.OldFullPath.EndsWith(ProjectFileExtension, FilePathComparison.Instance))
                {
                    // Renaming from project file to something else.
                    FileSystemWatcher_ProjectFileEvent_Background(args.OldFullPath, RazorFileChangeKind.Removed);
                }

                if (args.FullPath.EndsWith(ProjectFileExtension, FilePathComparison.Instance))
                {
                    // Renaming to a project file.
                    FileSystemWatcher_ProjectFileEvent_Background(args.FullPath, RazorFileChangeKind.Added);
                }
            };

            _watcher.EnableRaisingEvents = true;
        }
コード例 #3
0
        public async override Task <TagHelperDescriptor?> TryGetTagHelperDescriptorAsync(DocumentSnapshot documentSnapshot, CancellationToken cancellationToken)
        {
            // No point doing anything if its not a component
            if (documentSnapshot.FileKind != FileKinds.Component)
            {
                return(null);
            }

            var razorCodeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

            if (razorCodeDocument is null)
            {
                return(null);
            }

            var projects = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                () => _projectSnapshotManager.Projects.ToArray(),
                cancellationToken).ConfigureAwait(false);

            foreach (var project in projects)
            {
                // If the document is an import document, then it can't be a component
                if (project.IsImportDocument(documentSnapshot))
                {
                    return(null);
                }

                // If the document isn't in this project, then no point searching for components
                // This also avoids the issue of duplicate components
                if (!project.DocumentFilePaths.Contains(documentSnapshot.FilePath))
                {
                    return(null);
                }

                // If we got this far, we can check for tag helpers
                foreach (var tagHelper in project.TagHelpers)
                {
                    // Check the typename and namespace match
                    if (IsPathCandidateForComponent(documentSnapshot, tagHelper.GetTypeNameIdentifier()) &&
                        ComponentNamespaceMatchesFullyQualifiedName(razorCodeDocument, tagHelper.GetTypeNamespace()))
                    {
                        return(tagHelper);
                    }
                }
            }

            return(null);
        }
コード例 #4
0
        public async Task SolutionClosing_CancelsActiveWork()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Workspace)
            {
                AllowNotifyListeners = true,
            };
            var expectedProjectPath     = SomeProject.FilePath;
            var expectedProjectSnapshot = await Dispatcher.RunOnDispatcherThreadAsync(() =>
            {
                projectManager.ProjectAdded(SomeProject);
                projectManager.ProjectAdded(SomeOtherProject);

                return(projectManager.GetLoadedProject(SomeProject.FilePath));
            }, CancellationToken.None);

            var projectService = new Mock <TextBufferProjectService>(MockBehavior.Strict);

            projectService.Setup(p => p.GetProjectPath(It.IsAny <IVsHierarchy>())).Returns(expectedProjectPath);
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();

            var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(TestServiceProvider.Instance, projectService.Object, workspaceStateGenerator, Dispatcher, JoinableTaskFactory.Context);

            trigger.Initialize(projectManager);
            trigger.UpdateProjectCfg_Done(Mock.Of <IVsHierarchy>(MockBehavior.Strict), pCfgProj: default, pCfgSln: default, dwAction: default, fSuccess: default, fCancel: default);
コード例 #5
0
        private void HandleFileChangeEvent(FileChangeKind changeKind, FileEventArgs args)
        {
            if (Changed == null)
            {
                return;
            }

            foreach (var fileEvent in args)
            {
                if (fileEvent.IsDirectory)
                {
                    continue;
                }

                var normalizedEventPath = NormalizePath(fileEvent.FileName.FullPath);
                if (string.Equals(_normalizedFilePath, normalizedEventPath, StringComparison.OrdinalIgnoreCase))
                {
                    _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync((changeKind, ct) =>
                    {
                        OnChanged(changeKind);
                    }, changeKind, CancellationToken.None);
                    return;
                }
            }
        }
コード例 #6
0
        private void UpdateDocuments(HostProject hostProject, IEnumerable <IMSBuildItemEvaluated> projectItems)
        {
            var projectDirectory  = Path.GetDirectoryName(hostProject.FilePath);
            var documentFilePaths = GetRazorDocuments(projectDirectory, projectItems);

            var oldFiles     = _currentRazorFilePaths;
            var newFiles     = documentFilePaths.ToImmutableHashSet();
            var addedFiles   = newFiles.Except(oldFiles);
            var removedFiles = oldFiles.Except(newFiles);

            _currentRazorFilePaths = documentFilePaths;

            _ = ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                foreach (var document in removedFiles)
                {
                    RemoveDocument(hostProject, document);
                }

                foreach (var document in addedFiles)
                {
                    var relativeFilePath = document.Substring(projectDirectory.Length + 1);
                    AddDocument(hostProject, document, relativeFilePath);
                }
            },
                                                                            CancellationToken.None);
        }
コード例 #7
0
 private async Task InitializeSolutionAsync(Solution solution, CancellationToken cancellationToken)
 {
     try
     {
         await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
             () =>
         {
             base.InitializeSolution(solution);
         },
             cancellationToken).ConfigureAwait(false);
     }
     catch (Exception ex)
     {
         Debug.Fail("Unexpected error when initializing solution: " + ex);
     }
 }
コード例 #8
0
        private void Project_Disposing(object sender, EventArgs e)
        {
            _project.ProjectCapabilitiesChanged -= Project_ProjectCapabilitiesChanged;
            _project.Disposing -= Project_Disposing;

            _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => DetachCurrentRazorProjectHost(), CancellationToken.None);
        }
コード例 #9
0
        internal Task HandleEndBuildAsync(BuildEventArgs args)
        {
            if (!args.Success)
            {
                // Build failed
                return(Task.CompletedTask);
            }

            return(_projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync((projectItem, ct) =>
            {
                if (!_projectService.IsSupportedProject(projectItem))
                {
                    // We're hooked into all build events, it's possible to get called with an unsupported project item type.
                    return;
                }

                var projectPath = _projectService.GetProjectPath(projectItem);
                var projectSnapshot = _projectManager.GetLoadedProject(projectPath);
                if (projectSnapshot != null)
                {
                    var workspaceProject = _projectManager.Workspace.CurrentSolution?.Projects.FirstOrDefault(
                        project => FilePathComparer.Instance.Equals(project.FilePath, projectSnapshot.FilePath));
                    if (workspaceProject != null)
                    {
                        // Trigger a tag helper update by forcing the project manager to see the workspace Project
                        // from the current solution.
                        _workspaceStateGenerator.Update(workspaceProject, projectSnapshot, CancellationToken.None);
                    }
                }
            }, args.SolutionItem, CancellationToken.None));
        }
コード例 #10
0
        public void ProcessOpen(ITextBuffer textBuffer)
        {
            if (textBuffer == null)
            {
                throw new ArgumentNullException(nameof(textBuffer));
            }

            _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                () => _fileTracker.StopListening(), CancellationToken.None).ConfigureAwait(false);

            _snapshotTracker.StartTracking(textBuffer);
            EditorTextBuffer                 = textBuffer;
            EditorTextContainer              = textBuffer.AsTextContainer();
            EditorTextContainer.TextChanged += TextContainer_Changed;

            _opened?.Invoke(this, EventArgs.Empty);
        }
コード例 #11
0
            public override ValueTask ProcessAsync(CancellationToken cancellationToken)
            {
                var task = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                    () => _workspaceStateGenerator.Update(_workspaceProject, _projectSnapshot, cancellationToken),
                    cancellationToken);

                return(new ValueTask(task));
            }
            // We override the InitializeSolution in order to enforce calls to this to be on the project snapshot manager's
            // thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting
            // in change events dispatching through the Workspace on multiple different threads. This normalizes
            // that abnormality.
#pragma warning disable VSTHRD100 // Avoid async void methods
            protected override async void InitializeSolution(Solution solution)
#pragma warning restore VSTHRD100 // Avoid async void methods
            {
                await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                    () =>
                {
                    try
                    {
                        base.InitializeSolution(solution);
                    }
                    catch (Exception ex)
                    {
                        Debug.Fail("Unexpected error when initializing solution: " + ex);
                    }
                },
                    CancellationToken.None).ConfigureAwait(false);
            }
コード例 #13
0
 private async Task Document_ChangedOnDiskAsync(EditorDocument document, CancellationToken cancellationToken)
 {
     try
     {
         // This event is called by the EditorDocumentManager, which runs on the UI thread.
         // However, due to accessing the project snapshot manager, we need to switch to
         // running on the project snapshot manager's specialized thread.
         await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
         {
             ProjectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader);
         }, cancellationToken).ConfigureAwait(false);
     }
     catch (Exception ex)
     {
         Debug.Fail("EditorDocumentManagerListener.Document_ChangedOnDisk threw exception:" +
                    Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace);
     }
 }
コード例 #14
0
#pragma warning disable VSTHRD100 // Avoid async void methods
        private async void Document_ChangedOnDisk(object sender, EventArgs e)
#pragma warning restore VSTHRD100 // Avoid async void methods
        {
            try
            {
                // This event is called by the EditorDocumentManager, which runs on the UI thread.
                // However, due to accessing the project snapshot manager, we need to switch to
                // running on the project snapshot manager's specialized thread.
                await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
                {
                    var document = (EditorDocument)sender;
                    _projectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader);
                }, CancellationToken.None).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Debug.Fail("EditorDocumentManagerListener.Document_ChangedOnDisk threw exception:" +
                           Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace);
            }
        }
コード例 #15
0
        /// <summary>Search for a component in a project based on its tag name and fully qualified name.</summary>
        /// <remarks>
        /// This method makes several assumptions about the nature of components. First, it assumes that a component
        /// a given name `Name` will be located in a file `Name.razor`. Second, it assumes that the namespace the
        /// component is present in has the same name as the assembly its corresponding tag helper is loaded from.
        /// Implicitly, this method inherits any assumptions made by TrySplitNamespaceAndType.
        /// </remarks>
        /// <param name="tagHelper">A TagHelperDescriptor to find the corresponding Razor component for.</param>
        /// <returns>The corresponding DocumentSnapshot if found, null otherwise.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="tagHelper"/> is null.</exception>
        public override async Task <DocumentSnapshot> TryLocateComponentAsync(TagHelperDescriptor tagHelper)
        {
            if (tagHelper is null)
            {
                throw new ArgumentNullException(nameof(tagHelper));
            }

            if (!DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.TrySplitNamespaceAndType(tagHelper.Name, out var @namespaceName, out var typeName))
            {
                _logger.LogWarning($"Could not split namespace and type for name {tagHelper.Name}.");
                return(null);
            }

            var lookupSymbolName = RemoveGenericContent(typeName);

            var projects = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                () => _projectSnapshotManager.Projects.ToArray(),
                CancellationToken.None).ConfigureAwait(false);

            foreach (var project in projects)
            {
                foreach (var path in project.DocumentFilePaths)
                {
                    // Get document and code document
                    var documentSnapshot = project.GetDocument(path);

                    // Rule out if not Razor component with correct name
                    if (!IsPathCandidateForComponent(documentSnapshot, lookupSymbolName))
                    {
                        continue;
                    }

                    var razorCodeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

                    if (razorCodeDocument is null)
                    {
                        continue;
                    }

                    // Make sure we have the right namespace of the fully qualified name
                    if (!ComponentNamespaceMatchesFullyQualifiedName(razorCodeDocument, namespaceName))
                    {
                        continue;
                    }

                    return(documentSnapshot);
                }
            }

            return(null);
        }
コード例 #16
0
        public async override Task OnTextViewOpenedAsync(ITextView textView, IEnumerable <ITextBuffer> subjectBuffers)
        {
            if (textView is null)
            {
                throw new ArgumentNullException(nameof(textView));
            }

            if (subjectBuffers is null)
            {
                throw new ArgumentNullException(nameof(subjectBuffers));
            }

            _joinableTaskContext.AssertUIThread();

            foreach (var textBuffer in subjectBuffers)
            {
                if (!textBuffer.IsRazorBuffer())
                {
                    continue;
                }

                if (!_editorFactoryService.TryGetDocumentTracker(textBuffer, out var documentTracker) ||
                    !(documentTracker is DefaultVisualStudioDocumentTracker tracker))
                {
                    Debug.Fail("Tracker should always be available given our expectations of the VS workflow.");
                    return;
                }

                tracker.AddTextView(textView);

                if (documentTracker.TextViews.Count == 1)
                {
                    // tracker.Subscribe() accesses the project snapshot manager, which needs to be run on the
                    // project snapshot manager's specialized thread.
                    await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => tracker.Subscribe(), CancellationToken.None).ConfigureAwait(false);
                }
            }
        }
コード例 #17
0
        public DefaultProjectSnapshotManager(
            ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
            ErrorReporter errorReporter,
            IEnumerable <ProjectSnapshotChangeTrigger> triggers,
            Workspace workspace)
        {
            if (projectSnapshotManagerDispatcher is null)
            {
                throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
            }

            if (errorReporter is null)
            {
                throw new ArgumentNullException(nameof(errorReporter));
            }

            if (triggers is null)
            {
                throw new ArgumentNullException(nameof(triggers));
            }

            if (workspace is null)
            {
                throw new ArgumentNullException(nameof(workspace));
            }

            _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
            _errorReporter = errorReporter;
            _triggers      = triggers.OrderByDescending(trigger => trigger.InitializePriority).ToArray();
            Workspace      = workspace;

            _projects         = new Dictionary <string, Entry>(FilePathComparer.Instance);
            _openDocuments    = new HashSet <string>(FilePathComparer.Instance);
            _notificationWork = new Queue <ProjectChangeEventArgs>();

            // All methods involving the project snapshot manager need to be run on the
            // project snapshot manager's specialized thread. The LSP editor should already
            // be on the specialized thread, however the old editor may be calling this
            // constructor on the UI thread.
            if (_projectSnapshotManagerDispatcher.IsDispatcherThread)
            {
                InitializeTriggers(this, _triggers);
            }
            else
            {
                _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                    () => InitializeTriggers(this, _triggers), CancellationToken.None);
            }
        internal Task OnProjectBuiltAsync(IVsHierarchy projectHierarchy, CancellationToken cancellationToken)
        {
            var projectFilePath = _projectService.GetProjectPath(projectHierarchy);

            return(_projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                var projectSnapshot = _projectManager.GetLoadedProject(projectFilePath);
                if (projectSnapshot != null)
                {
                    var workspaceProject = _projectManager.Workspace.CurrentSolution.Projects.FirstOrDefault(
                        wp => FilePathComparer.Instance.Equals(wp.FilePath, projectSnapshot.FilePath));
                    if (workspaceProject != null)
                    {
                        // Trigger a tag helper update by forcing the project manager to see the workspace Project
                        // from the current solution.
                        _workspaceStateGenerator.Update(workspaceProject, projectSnapshot, cancellationToken);
                    }
                }
            }, cancellationToken));
        }
コード例 #19
0
#pragma warning disable VSTHRD100 // Avoid async void methods
        private async void Timer_Tick(object state)
#pragma warning restore VSTHRD100 // Avoid async void methods
        {
            try
            {
                OnStartingBackgroundWork();

                KeyValuePair <string, DocumentSnapshot>[] work;
                lock (_work)
                {
                    work = _work.ToArray();
                    _work.Clear();
                }

                OnBackgroundCapturedWorkload();

                for (var i = 0; i < work.Length; i++)
                {
                    if (_solutionIsClosing)
                    {
                        break;
                    }

                    var document = work[i].Value;
                    try
                    {
                        await document.GetGeneratedOutputAsync().ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        ReportError(ex);
                    }
                }

                OnCompletingBackgroundWork();

                if (_documentProcessedListeners.Count != 0 && !_solutionIsClosing)
                {
                    await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                        () => NotifyDocumentsProcessed(work),
                        CancellationToken.None).ConfigureAwait(false);
                }

                lock (_work)
                {
                    // Resetting the timer allows another batch of work to start.
                    _timer.Dispose();
                    _timer = null;

                    // If more work came in while we were running start the worker again.
                    if (_work.Count > 0 && !_solutionIsClosing)
                    {
                        StartWorker();
                    }
                }

                OnCompletedBackgroundWork();
            }
            catch (Exception ex)
            {
                // This is something totally unexpected, let's just send it over to the workspace.
                ReportError(ex);

                _timer?.Dispose();
                _timer = null;
            }
        }
コード例 #20
0
        public EditorDocument(
            EditorDocumentManager documentManager,
            ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
            JoinableTaskContext joinableTaskContext,
            string projectFilePath,
            string documentFilePath,
            TextLoader textLoader,
            FileChangeTracker fileTracker,
            ITextBuffer textBuffer,
            EventHandler changedOnDisk,
            EventHandler changedInEditor,
            EventHandler opened,
            EventHandler closed)
        {
            if (documentManager is null)
            {
                throw new ArgumentNullException(nameof(documentManager));
            }

            if (projectSnapshotManagerDispatcher is null)
            {
                throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
            }

            if (joinableTaskContext is null)
            {
                throw new ArgumentNullException(nameof(joinableTaskContext));
            }

            if (projectFilePath is null)
            {
                throw new ArgumentNullException(nameof(projectFilePath));
            }

            if (documentFilePath is null)
            {
                throw new ArgumentNullException(nameof(documentFilePath));
            }

            if (textLoader is null)
            {
                throw new ArgumentNullException(nameof(textLoader));
            }

            if (fileTracker is null)
            {
                throw new ArgumentNullException(nameof(fileTracker));
            }

            _documentManager = documentManager;
            _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
            _joinableTaskContext = joinableTaskContext;
            ProjectFilePath      = projectFilePath;
            DocumentFilePath     = documentFilePath;
            TextLoader           = textLoader;
            _fileTracker         = fileTracker;
            _changedOnDisk       = changedOnDisk;
            _changedInEditor     = changedInEditor;
            _opened = opened;
            _closed = closed;

            _snapshotTracker      = new SnapshotChangeTracker();
            _fileTracker.Changed += ChangeTracker_Changed;

            // Only one of these should be active at a time.
            if (textBuffer == null)
            {
                _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
                    () => _fileTracker.StartListening(), CancellationToken.None).ConfigureAwait(false);
            }
            else
            {
                _snapshotTracker.StartTracking(textBuffer);

                EditorTextBuffer                 = textBuffer;
                EditorTextContainer              = textBuffer.AsTextContainer();
                EditorTextContainer.TextChanged += TextContainer_Changed;
            }
        }
コード例 #21
0
 protected Task UpdateAsync(Action action, CancellationToken cancellationToken)
 => _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken);
コード例 #22
0
        public async Task <RazorLanguageQueryResponse> Handle(RazorLanguageQueryParams request, CancellationToken cancellationToken)
        {
            int?documentVersion = null;
            DocumentSnapshot documentSnapshot = null;
            await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                _documentResolver.TryResolveDocument(request.Uri.GetAbsoluteOrUNCPath(), out documentSnapshot);

                Debug.Assert(documentSnapshot != null, "Failed to get the document snapshot, could not map to document ranges.");

                if (!_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out documentVersion))
                {
                    // This typically happens for closed documents.
                    documentVersion = null;
                }

                return(documentSnapshot);
            }, cancellationToken).ConfigureAwait(false);

            var codeDocument = await documentSnapshot.GetGeneratedOutputAsync();

            var sourceText = await documentSnapshot.GetTextAsync();

            var linePosition      = new LinePosition(request.Position.Line, request.Position.Character);
            var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition);
            var responsePosition  = request.Position;

            if (codeDocument.IsUnsupported())
            {
                // All language queries on unsupported documents return Html. This is equivalent to what pre-VSCode Razor was capable of.
                return(new RazorLanguageQueryResponse()
                {
                    Kind = RazorLanguageKind.Html,
                    Position = responsePosition,
                    PositionIndex = hostDocumentIndex,
                    HostDocumentVersion = documentVersion,
                });
            }

            var responsePositionIndex = hostDocumentIndex;

            var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex);

            if (languageKind == RazorLanguageKind.CSharp)
            {
                if (_documentMappingService.TryMapToProjectedDocumentPosition(codeDocument, hostDocumentIndex, out var projectedPosition, out var projectedIndex))
                {
                    // For C# locations, we attempt to return the corresponding position
                    // within the projected document
                    responsePosition      = projectedPosition;
                    responsePositionIndex = projectedIndex;
                }
                else
                {
                    // It no longer makes sense to think of this location as C#, since it doesn't
                    // correspond to any position in the projected document. This should not happen
                    // since there should be source mappings for all the C# spans.
                    languageKind          = RazorLanguageKind.Razor;
                    responsePositionIndex = hostDocumentIndex;
                }
            }
コード例 #23
0
 private async Task DocumentClosedTimer_TickAsync(CancellationToken cancellationToken)
 {
     await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
         ClearClosedDocuments,
         cancellationToken).ConfigureAwait(false);
 }
コード例 #24
0
 private async Task UpdateDocumentAsync(int newVersion, DocumentSnapshot documentSnapshot)
 {
     await ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
         () => VersionCache.TrackDocumentVersion(documentSnapshot, newVersion), CancellationToken.None).ConfigureAwait(false);
 }