提交 475d1d15 编写于 作者: C CyrusNajmabadi

Extra delay loading of service into its own class.

上级 13859e84
......@@ -136,7 +136,10 @@ protected virtual ImmutableArray<CompletionProvider> GetProviders(ImmutableHashS
{
var map = ImmutableDictionary<string, CompletionProvider>.Empty;
foreach (var provider in GetBuiltInProviders().Concat(GetImportedProviders().Select(lz => lz.Value)).Concat(_testProviders))
var importedProviders = GetImportedProviders().Where(lz => lz.Metadata.Language == this.Language)
.Select(lz => lz.Value);
foreach (var provider in GetBuiltInProviders().Concat(importedProviders).Concat(_testProviders))
{
if (!map.ContainsKey(provider.Name))
{
......
......@@ -155,6 +155,7 @@
<Compile Include="Implementation\Workspace\VisualStudioProjectCacheHostServiceFactory.cs" />
<Compile Include="IRoslynTelemetrySetup.cs" />
<Compile Include="Packaging\Interop\SVsRemoteControlService.cs" />
<Compile Include="SymbolSearch\AbstractDelayStartedService.cs" />
<Compile Include="SymbolSearch\IAddReferenceDatabaseWrapper.cs" />
<Compile Include="SymbolSearch\IDatabaseFactoryService.cs" />
<Compile Include="SymbolSearch\IDelayService.cs" />
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal abstract class AbstractDelayStartedService : ForegroundThreadAffinitizedObject
{
protected readonly List<string> RegisteredLanguageNames = new List<string>();
protected readonly Workspace Workspace;
// Option that controls if this service is enabled or not (regardless of language).
private readonly Option<bool> _serviceOnOffOption;
// Options that control if this service is enabled or not for a particular language.
private readonly ImmutableArray<PerLanguageOption<bool>> _perLanguageOptions;
protected AbstractDelayStartedService(
Workspace workspace,
Option<bool> onOffOption,
params PerLanguageOption<bool>[] perLanguageOptions)
{
Workspace = workspace;
_serviceOnOffOption = onOffOption;
_perLanguageOptions = perLanguageOptions.ToImmutableArray();
}
protected abstract void StartWork();
protected abstract void StopWork();
protected abstract void ConnectToAdditionalEventSources();
protected abstract void DisconnectFromAdditionalEventSources();
internal void Start(string languageName)
{
this.AssertIsForeground();
this.RegisteredLanguageNames.Add(languageName);
if (this.RegisteredLanguageNames.Count == 1)
{
// When the first language registers, start the service.
var options = Workspace.Options;
if (!options.GetOption(_serviceOnOffOption))
{
// Feature is totally disabled. Do nothing.
return;
}
// Register to hear about option changing.
var optionsService = Workspace.Services.GetService<IOptionService>();
optionsService.OptionChanged += OnOptionChanged;
// Start the whole process once we're connected
ConnectToAdditionalEventSources();
}
// Kick things off.
OnOptionChanged(this, EventArgs.Empty);
}
protected void OnOptionChanged(object sender, EventArgs e)
{
if (!RegisteredLanguageNames.Any(IsRegisteredForLanguage))
{
// The feature is not enabled for any registered languages.
return;
}
StartWork();
}
private bool IsRegisteredForLanguage(string language)
{
var options = Workspace.Options;
return _perLanguageOptions.Any(o => options.GetOption(o, language));
}
internal void Stop(string languageName)
{
RegisteredLanguageNames.Remove(languageName);
if (RegisteredLanguageNames.Count == 0)
{
// once there are no more languages registered, we can actually stop this service.
var optionsService = Workspace.Services.GetService<IOptionService>();
optionsService.OptionChanged -= OnOptionChanged;
DisconnectFromAdditionalEventSources();
StopWork();
}
}
}
}
\ No newline at end of file
......@@ -69,36 +69,6 @@ internal partial class SymbolSearchService
private void LogException(Exception e, string text) => _logService.LogException(e, text);
private void OnOptionChanged(object sender, EventArgs e)
{
// If we don't have any add-import features that would use these indices, then
// don't bother creating them.
if (!_registeredLanguageNames.Any(IsRegisteredForLanguage))
{
return;
}
// Kick off a database update. Wait a few seconds before starting so we don't
// interfere too much with solution loading.
var sources = _installerService.PackageSources;
// Always pull down the nuget.org index. It contains the MS reference assembly index
// inside of it.
var allSources = sources.Concat(new PackageSource(NugetOrgSource, source: null));
foreach (var source in allSources)
{
Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ =>
UpdateSourceInBackgroundAsync(source.Name), TaskScheduler.Default);
}
}
private bool IsRegisteredForLanguage(string language)
{
var options = _workspace.Options;
return options.GetOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, language) ||
options.GetOption(AddImportOptions.SuggestForTypesInNuGetPackages, language);
}
// internal for testing purposes.
internal Task UpdateSourceInBackgroundAsync(string source)
......
......@@ -6,8 +6,8 @@
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.Elfie.Model.Structures;
using Microsoft.CodeAnalysis.Elfie.Model.Tree;
......@@ -15,13 +15,13 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Settings;
using Roslyn.Utilities;
using VSShell = Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
......@@ -34,15 +34,13 @@ namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
/// date by downloading patches on a daily basis.
/// </summary>
[ExportWorkspaceService(typeof(ISymbolSearchService)), Shared]
internal partial class SymbolSearchService : ForegroundThreadAffinitizedObject, ISymbolSearchService
internal partial class SymbolSearchService : AbstractDelayStartedService, ISymbolSearchService
{
private readonly Workspace _workspace;
private ConcurrentDictionary<string, IAddReferenceDatabaseWrapper> _sourceToDatabase =
new ConcurrentDictionary<string, IAddReferenceDatabaseWrapper>();
private readonly List<string> _registeredLanguageNames = new List<string>();
[ImportingConstructor]
public SymbolSearchService(
VisualStudioWorkspaceImpl workspace,
......@@ -88,7 +86,10 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi
IDatabaseFactoryService databaseFactoryService,
string localSettingsDirectory,
Func<Exception, bool> reportAndSwallowException,
CancellationTokenSource cancellationTokenSource)
CancellationTokenSource cancellationTokenSource)
: base(workspace, ServiceComponentOnOffOptions.SymbolSearch,
AddImportOptions.SuggestForTypesInReferenceAssemblies,
AddImportOptions.SuggestForTypesInNuGetPackages)
{
if (remoteControlService == null)
{
......@@ -111,46 +112,38 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi
_cancellationToken = _cancellationTokenSource.Token;
}
internal void Start(string languageName)
protected override void ConnectToAdditionalEventSources()
{
_registeredLanguageNames.Add(languageName);
if (_registeredLanguageNames.Count == 1)
{
// When the first language registers, start the service.
var options = _workspace.Options;
if (!options.GetOption(ServiceComponentOnOffOptions.SymbolSearch))
{
return;
}
var optionsService = _workspace.Services.GetService<IOptionService>();
optionsService.OptionChanged += OnOptionChanged;
// Start the whole process once we're connected
_installerService.PackageSourcesChanged += OnOptionChanged;
}
_installerService.PackageSourcesChanged += OnOptionChanged;
}
// Kick things off.
OnOptionChanged(this, EventArgs.Empty);
protected override void DisconnectFromAdditionalEventSources()
{
_installerService.PackageSourcesChanged -= OnOptionChanged;
}
internal void Stop(string languageName)
protected override void StartWork()
{
_registeredLanguageNames.Remove(languageName);
if (_registeredLanguageNames.Count == 0)
// Kick off a database update. Wait a few seconds before starting so we don't
// interfere too much with solution loading.
var sources = _installerService.PackageSources;
// Always pull down the nuget.org index. It contains the MS reference assembly index
// inside of it.
var allSources = sources.Concat(new PackageSource(NugetOrgSource, source: null));
foreach (var source in allSources)
{
// once there are no more languages registered, we can actually stop this service.
var optionsService = _workspace.Services.GetService<IOptionService>();
optionsService.OptionChanged -= OnOptionChanged;
_installerService.PackageSourcesChanged -= OnOptionChanged;
// Cancel any existing work.
_cancellationTokenSource.Cancel();
Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ =>
UpdateSourceInBackgroundAsync(source.Name), TaskScheduler.Default);
}
}
protected override void StopWork()
{
// Cancel any existing work.
_cancellationTokenSource.Cancel();
}
public IEnumerable<PackageWithTypeResult> FindPackagesWithType(
string source, string name, int arity, CancellationToken cancellationToken)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册