|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.SolutionCrawler;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
{
/// <summary>
/// A version of ITableDataSource who knows how to connect them to Roslyn solution crawler for live information.
/// </summary>
internal abstract class AbstractRoslynTableDataSource<TItem, TData> : AbstractTableDataSource<TItem, TData>
where TItem : TableItem
where TData : notnull
{
public AbstractRoslynTableDataSource(Workspace workspace, IThreadingContext threadingContext)
: base(workspace, threadingContext)
=> ConnectToSolutionCrawlerService(workspace);
protected ImmutableArray<DocumentId> GetDocumentsWithSameFilePath(Solution solution, DocumentId documentId)
{
var document = solution.GetTextDocument(documentId);
if (document == null)
{
return ImmutableArray<DocumentId>.Empty;
}
return solution.GetDocumentIdsWithFilePath(document.FilePath);
}
/// <summary>
/// Flag indicating if a solution crawler is running incremental analyzers in background.
/// We get build progress updates from <see cref="ISolutionCrawlerProgressReporter.ProgressChanged"/>.
/// Solution crawler progress events are guaranteed to be invoked in a serial fashion.
/// </summary>
protected bool IsSolutionCrawlerRunning { get; private set; }
private void ConnectToSolutionCrawlerService(Workspace workspace)
{
var crawlerService = workspace.Services.GetService<ISolutionCrawlerService>();
if (crawlerService == null)
{
// can happen depends on host such as testing host.
return;
}
var reporter = crawlerService.GetProgressReporter(workspace);
reporter.ProgressChanged += OnSolutionCrawlerProgressChanged;
// set initial value
SolutionCrawlerProgressChanged(reporter.InProgress);
}
private void OnSolutionCrawlerProgressChanged(object sender, ProgressData progressData)
{
switch (progressData.Status)
{
case ProgressStatus.Started:
SolutionCrawlerProgressChanged(running: true);
break;
case ProgressStatus.Stopped:
SolutionCrawlerProgressChanged(running: false);
break;
}
}
private void SolutionCrawlerProgressChanged(bool running)
{
IsSolutionCrawlerRunning = running;
ChangeStableStateIfRequired(newIsStable: !IsSolutionCrawlerRunning);
}
protected void ChangeStableStateIfRequired(bool newIsStable)
{
var oldIsStable = IsStable;
if (oldIsStable != newIsStable)
{
IsStable = newIsStable;
ChangeStableState(newIsStable);
}
}
}
}
|