Пример #1
0
        public async Task <Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(notification.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);

            var sourceText = await document.GetTextAsync();

            sourceText = ApplyContentChanges(notification.ContentChanges, sourceText);

            if (notification.TextDocument.Version is null)
            {
                throw new InvalidOperationException("Provided version should not be null.");
            }

            await Task.Factory.StartNew(
                () => _projectService.UpdateDocument(document.FilePath, sourceText, notification.TextDocument.Version.Value),
                CancellationToken.None,
                TaskCreationOptions.None,
                _foregroundDispatcher.ForegroundScheduler);

            return(Unit.Value);
        }
        public async Task <Unit> Handle(AddDocumentParams request, CancellationToken cancellationToken)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            await Task.Factory.StartNew(
                () => _projectService.AddDocument(request.FilePath),
                CancellationToken.None,
                TaskCreationOptions.None,
                _foregroundDispatcher.ForegroundScheduler);

            return(Unit.Value);
        }
        protected override async Task OnProjectChangedAsync()
        {
            ForegroundDispatcher.AssertBackgroundThread();

            await ExecuteWithLockAsync(async() =>
            {
                var referencedAssemblies = await DotNetProject.GetReferencedAssemblies(ConfigurationSelector.Default);
                var mvcReference         = referencedAssemblies.FirstOrDefault(IsMvcAssembly);

                if (mvcReference == null)
                {
                    // Ok we can't find an MVC version. Let's assume this project isn't using Razor then.
                    await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
                    return;
                }

                var version = GetAssemblyVersion(mvcReference.FilePath);
                if (version == null)
                {
                    // Ok we can't find an MVC version. Let's assume this project isn't using Razor then.
                    await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
                    return;
                }

                var configuration = FallbackRazorConfiguration.SelectConfiguration(version);
                var hostProject   = new HostProject(DotNetProject.FileName.FullPath, configuration);
                await UpdateHostProjectUnsafeAsync(hostProject).ConfigureAwait(false);
            });
        }
        public async Task <Uri> GetProjectPathAsync(Uri documentFilePath, CancellationToken cancellationToken)
        {
            if (documentFilePath == null)
            {
                throw new ArgumentNullException(nameof(documentFilePath));
            }

            _foregroundDispatcher.AssertBackgroundThread();

            await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            if (_openDocumentShell == null)
            {
                _openDocumentShell = ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
            }

            var hostDocumentFilePath = _session.ConvertSharedUriToLocalPath(documentFilePath);
            var hr = _openDocumentShell.IsDocumentInAProject(hostDocumentFilePath, out var hierarchy, out _, out _, out _);

            if (ErrorHandler.Succeeded(hr) && hierarchy != null)
            {
                ErrorHandler.ThrowOnFailure(((IVsProject)hierarchy).GetMkDocument((uint)VSConstants.VSITEMID.Root, out var path), VSConstants.E_NOTIMPL);

                return(_session.ConvertLocalPathToSharedUri(path));
            }

            return(null);
        }
        private void Onidle(object sender, ElapsedEventArgs e)
        {
            _dispatcher.AssertBackgroundThread();

            var textViews = Array.Empty <ITextView>();

            foreach (var textView in textViews)
            {
                if (_completionBroker.IsCompletionActive(textView))
                {
                    return;
                }
            }

            _idleTimer.Stop();
            Reparse();
        }
        public async Task <CompletionContext> GetCompletionContextAsync(
            IAsyncCompletionSession session,
            CompletionTrigger trigger,
            SnapshotPoint triggerLocation,
            SnapshotSpan applicableSpan,
            CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            try
            {
                var codeDocument = await _parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token);

                if (codeDocument == null)
                {
                    return(CompletionContext.Empty);
                }

                var location   = new SourceSpan(triggerLocation.Position, 0);
                var syntaxTree = codeDocument.GetSyntaxTree();
                var tagHelperDocumentContext = codeDocument.GetTagHelperContext();
                var razorCompletionItems     = _completionFactsService.GetCompletionItems(syntaxTree, tagHelperDocumentContext, location);

                var completionItems = new List <CompletionItem>();
                foreach (var razorCompletionItem in razorCompletionItems)
                {
                    if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive)
                    {
                        // Don't support any other types of completion kinds other than directives.
                        continue;
                    }

                    var completionItem = new CompletionItem(
                        displayText: razorCompletionItem.DisplayText,
                        filterText: razorCompletionItem.DisplayText,
                        insertText: razorCompletionItem.InsertText,
                        source: this,
                        icon: DirectiveImageGlyph,
                        filters: DirectiveCompletionFilters,
                        suffix: string.Empty,
                        sortText: razorCompletionItem.DisplayText,
                        attributeIcons: ImmutableArray <ImageElement> .Empty);
                    var completionDescription = razorCompletionItem.GetDirectiveCompletionDescription();
                    completionItem.Properties.AddProperty(DescriptionKey, completionDescription);
                    completionItems.Add(completionItem);
                }
                var context = new CompletionContext(completionItems.ToImmutableArray());
                return(context);
            }
            catch (OperationCanceledException)
            {
                return(CompletionContext.Empty);
            }
        }
Пример #7
0
        public async Task <CompletionList> Handle(CompletionParams request, CancellationToken cancellationToken)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(request.TextDocument.Uri.AbsolutePath, out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);

            var codeDocument = await document.GetGeneratedOutputAsync();

            var syntaxTree = codeDocument.GetSyntaxTree();

            var sourceText = await document.GetTextAsync();

            var linePosition      = new LinePosition((int)request.Position.Line, (int)request.Position.Character);
            var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition);
            var location          = new SourceSpan(hostDocumentIndex, 0);

            var razorCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, location);

            _logger.LogTrace($"Found {razorCompletionItems.Count} Razor specific completion items.");

            var completionItems = new List <CompletionItem>();

            foreach (var razorCompletionItem in razorCompletionItems)
            {
                if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive)
                {
                    // Don't support any other types of completion kinds other than directives.
                    continue;
                }

                var directiveCompletionItem = new CompletionItem()
                {
                    Label         = razorCompletionItem.DisplayText,
                    InsertText    = razorCompletionItem.InsertText,
                    Detail        = razorCompletionItem.Description,
                    Documentation = razorCompletionItem.Description,
                    FilterText    = razorCompletionItem.DisplayText,
                    SortText      = razorCompletionItem.DisplayText,
                    Kind          = CompletionItemKind.Struct,
                };

                completionItems.Add(directiveCompletionItem);
            }

            var completionList = new CompletionList(completionItems, isIncomplete: false);

            return(completionList);
        }
Пример #8
0
        public async Task <Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(notification.TextDocument.Uri.AbsolutePath, out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);

            var sourceText = await document.GetTextAsync();

            sourceText = ApplyContentChanges(notification.ContentChanges, sourceText);

            await Task.Factory.StartNew(
                () => _projectService.UpdateDocument(document.FilePath, sourceText, notification.TextDocument.Version),
                CancellationToken.None,
                TaskCreationOptions.None,
                _foregroundDispatcher.ForegroundScheduler);

            return(Unit.Value);
        }
Пример #9
0
        private async void Timer_Tick(object state) // Yeah I know.
        {
            try
            {
                _foregroundDispatcher.AssertBackgroundThread();

                // Timer is stopped.
                _timer.Change(Timeout.Infinite, Timeout.Infinite);

                OnStartingBackgroundWork();

                ProjectSnapshotUpdateContext[] work;
                lock (_projects)
                {
                    work = _projects.Values.ToArray();
                    _projects.Clear();
                }

                var updates = new(ProjectSnapshotUpdateContext context, Exception exception)[work.Length];
        protected override async Task OnProjectChangedAsync()
        {
            ForegroundDispatcher.AssertBackgroundThread();

            await ExecuteWithLockAsync(async() =>
            {
                var projectProperties = DotNetProject.MSBuildProject.EvaluatedProperties;
                var projectItems      = DotNetProject.MSBuildProject.EvaluatedItems;

                if (TryGetConfiguration(projectProperties, projectItems, out var configuration))
                {
                    var hostProject = new HostProject(DotNetProject.FileName.FullPath, configuration);
                    await UpdateHostProjectUnsafeAsync(hostProject).ConfigureAwait(false);
                }
                else
                {
                    // Ok we can't find a configuration. Let's assume this project isn't using Razor then.
                    await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
                }
            });
        }
        public Task <CompletionContext> GetCompletionContextAsync(
            IAsyncCompletionSession session,
            CompletionTrigger trigger,
            SnapshotPoint triggerLocation,
            SnapshotSpan applicableSpan,
            CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var syntaxTree           = _parser.CodeDocument?.GetSyntaxTree();
            var location             = new SourceSpan(applicableSpan.Start.Position, applicableSpan.Length);
            var razorCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, location);

            var completionItems = new List <CompletionItem>();

            foreach (var razorCompletionItem in razorCompletionItems)
            {
                if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive)
                {
                    // Don't support any other types of completion kinds other than directives.
                    continue;
                }

                var completionItem = new CompletionItem(
                    displayText: razorCompletionItem.DisplayText,
                    filterText: razorCompletionItem.DisplayText,
                    insertText: razorCompletionItem.InsertText,
                    source: this,
                    icon: DirectiveImageGlyph,
                    filters: DirectiveCompletionFilters,
                    suffix: string.Empty,
                    sortText: razorCompletionItem.DisplayText,
                    attributeIcons: ImmutableArray <ImageElement> .Empty);
                completionItem.Properties.AddProperty(DescriptionKey, razorCompletionItem.Description);
                completionItems.Add(completionItem);
            }
            var context = new CompletionContext(completionItems.ToImmutableArray());

            return(Task.FromResult(context));
        }
Пример #12
0
        public async Task <CompletionList> Handle(CompletionParams request, CancellationToken cancellationToken)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);

            if (document is null || cancellationToken.IsCancellationRequested)
            {
                return(new CompletionList(isIncomplete: false));
            }

            var codeDocument = await document.GetGeneratedOutputAsync();

            if (codeDocument.IsUnsupported())
            {
                return(new CompletionList(isIncomplete: false));
            }

            var syntaxTree = codeDocument.GetSyntaxTree();
            var tagHelperDocumentContext = codeDocument.GetTagHelperContext();

            var sourceText = await document.GetTextAsync();

            var linePosition      = new LinePosition((int)request.Position.Line, (int)request.Position.Character);
            var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition);
            var location          = new SourceSpan(hostDocumentIndex, 0);

            var razorCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, tagHelperDocumentContext, location);

            _logger.LogTrace($"Resolved {razorCompletionItems.Count} completion items.");

            var completionList = CreateLSPCompletionList(razorCompletionItems);

            return(completionList);
        }
        // Must be called inside the lock.
        protected async Task UpdateHostProjectUnsafeAsync(HostProject newHostProject)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            await Task.Factory.StartNew(UpdateHostProjectForeground, newHostProject, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.ForegroundScheduler);
        }
Пример #14
0
        public async Task <CompletionList> Handle(CompletionParams request, CancellationToken cancellationToken)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot);

                return(documentSnapshot);
            }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);

            if (document is null || cancellationToken.IsCancellationRequested)
            {
                return(new CompletionList(isIncomplete: false));
            }

            var codeDocument = await document.GetGeneratedOutputAsync();

            if (codeDocument.IsUnsupported())
            {
                return(new CompletionList(isIncomplete: false));
            }

            var syntaxTree = codeDocument.GetSyntaxTree();
            var tagHelperDocumentContext = codeDocument.GetTagHelperContext();

            var sourceText = await document.GetTextAsync();

            var linePosition      = new LinePosition((int)request.Position.Line, (int)request.Position.Character);
            var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition);
            var location          = new SourceSpan(hostDocumentIndex, 0);

            var directiveCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, tagHelperDocumentContext, location);

            _logger.LogTrace($"Found {directiveCompletionItems.Count} directive completion items.");

            var completionItems = new List <CompletionItem>();

            foreach (var razorCompletionItem in directiveCompletionItems)
            {
                if (TryConvert(razorCompletionItem, out var completionItem))
                {
                    completionItems.Add(completionItem);
                }
            }

            var parameterCompletions = completionItems.Where(completionItem => completionItem.TryGetRazorCompletionKind(out var completionKind) && completionKind == RazorCompletionItemKind.DirectiveAttributeParameter);

            if (parameterCompletions.Any())
            {
                // Parameters are present in the completion list, even though TagHelpers are technically valid we shouldn't flood the completion list
                // with non parameter completions. Filter out the rest.
                completionItems = parameterCompletions.ToList();
            }
            else
            {
                var tagHelperCompletionItems = _tagHelperCompletionService.GetCompletionsAt(location, codeDocument);

                _logger.LogTrace($"Found {tagHelperCompletionItems.Count} TagHelper completion items.");

                completionItems.AddRange(tagHelperCompletionItems);
            }

            var completionList = new CompletionList(completionItems, isIncomplete: false);

            return(completionList);
        }
#pragma warning disable VSTHRD100 // Avoid async void methods
        private async void Timer_Tick(object state)
#pragma warning restore VSTHRD100 // Avoid async void methods
        {
            try
            {
                _foregroundDispatcher.AssertBackgroundThread();

                OnStartingBackgroundWork();

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

                OnBackgroundCapturedWorkload();

                for (var i = 0; i < work.Length; i++)
                {
                    var document = work[i].Value;
                    try
                    {
                        await document.GetGeneratedOutputAsync();
                    }
                    catch (Exception ex)
                    {
                        ReportError(ex);
                    }
                }

                OnCompletingBackgroundWork();

                await Task.Factory.StartNew(
                    () =>
                {
                    NotifyDocumentsProcessed(work);
                },
                    CancellationToken.None,
                    TaskCreationOptions.None,
                    _foregroundDispatcher.ForegroundScheduler);

                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)
                    {
                        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;
            }
        }
Пример #16
0
        private async void Timer_Tick(object state)
        {
            try
            {
                _foregroundDispatcher.AssertBackgroundThread();

                // Timer is stopped.
                _timer.Change(Timeout.Infinite, Timeout.Infinite);

                OnStartingBackgroundWork();

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

                OnBackgroundCapturedWorkload();

                for (var i = 0; i < work.Length; i++)
                {
                    var document = work[i].Value;
                    try
                    {
                        await document.GetGeneratedOutputAsync();
                    }
                    catch (Exception ex)
                    {
                        ReportError(ex);
                        _logger.LogError("Error when processing document: " + document.FilePath);
                    }
                }

                OnCompletingBackgroundWork();

                await Task.Factory.StartNew(
                    () => ReportUnsynchronizableContent(work),
                    CancellationToken.None,
                    TaskCreationOptions.None,
                    _foregroundDispatcher.ForegroundScheduler);

                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)
                    {
                        StartWorker();
                    }
                }

                OnCompletedBackgroundWork();
            }
            catch (Exception ex)
            {
                // This is something totally unexpected, let's just send it over to the workspace.
                ReportError(ex);
            }
        }
Пример #17
0
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            try
            {
                var codeDocument = await _parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token);

                if (codeDocument == null)
                {
                    // Code document not available yet.
                    return(CompletionContext.Empty);
                }

                var syntaxTree = codeDocument.GetSyntaxTree();
                var tagHelperDocumentContext = codeDocument.GetTagHelperContext();
                var location             = new SourceSpan(triggerLocation.Position, 0);
                var razorCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, tagHelperDocumentContext, location);

                if (razorCompletionItems.Count == 0)
                {
                    return(CompletionContext.Empty);
                }

                // Check if we're providing completion items while a legacy completion session is active. If so
                // we'll need to dismiss the legacy completion session to ensure we don't get two completion lists.
                var activeSessions = _completionBroker.GetSessions(session.TextView);
                foreach (var activeSession in activeSessions)
                {
                    if (activeSession.Properties.ContainsProperty(nameof(IAsyncCompletionSession)))
                    {
                        continue;
                    }

                    // Legacy completion is also active, we need to dismiss it.

                    _ = Task.Factory.StartNew(
                        () => activeSession.Dismiss(),
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        _foregroundDispatcher.ForegroundScheduler);
                }

                var completionItems     = new List <CompletionItem>();
                var completionItemKinds = new HashSet <RazorCompletionItemKind>();
                foreach (var razorCompletionItem in razorCompletionItems)
                {
                    if (razorCompletionItem.Kind != RazorCompletionItemKind.DirectiveAttribute &&
                        razorCompletionItem.Kind != RazorCompletionItemKind.DirectiveAttributeParameter)
                    {
                        // Don't support any other types of completion kinds other than directive attributes and their parameters.
                        continue;
                    }

                    var completionItem = new CompletionItem(
                        displayText: razorCompletionItem.DisplayText,
                        filterText: razorCompletionItem.DisplayText,
                        insertText: razorCompletionItem.InsertText,
                        source: this,
                        icon: DirectiveAttributeImageGlyph,
                        filters: DirectiveAttributeCompletionFilters,
                        suffix: string.Empty,
                        sortText: razorCompletionItem.DisplayText,
                        attributeIcons: ImmutableArray <ImageElement> .Empty);
                    completionItems.Add(completionItem);
                    completionItemKinds.Add(razorCompletionItem.Kind);

                    var completionDescription = razorCompletionItem.GetAttributeCompletionDescription();
                    completionItem.Properties[DescriptionKey] = completionDescription;
                }

                session.Properties.SetCompletionItemKinds(completionItemKinds);
                var orderedCompletionItems = completionItems.OrderBy(item => item.DisplayText);
                var context = new CompletionContext(orderedCompletionItems.ToImmutableArray());
                return(context);
            }
            catch (OperationCanceledException)
            {
                return(CompletionContext.Empty);
            }
        }