зеркало из https://github.com/dotnet/razor.git
Remove ProjectSnapshotManagerDispatcher usage in Visual Studio layer (#10211)
Long ago, `ProjectSnapshotManagerDispatcher` was introduced as a replacement for a lot of code in Razor that synchronized by running on the UI thread. This abstraction was needed for the language server, where there isn't a UI thread. However, there's a lot of code that was refactored to use `ProjectSnapshotManagerDispatcher` that doesn't really need it. After all the dispatcher is intended for scheduling updates to the project snapshot manager. So, using it for services that don't depend on the project snapshot manager is overuse. This change removes usage of `ProjectSnapshotManagerDispatcher` in most of the Visual Studio layer. It's still used by the `ProjectWorkspaceStateGenerator`, but that requires a larger refactoring. Most services that were using `ProjectSnapshotManagerDispatcher` did so to control updates to shared data structures, and made these free-threaded.
This commit is contained in:
Коммит
badd53cb7b
|
@ -2,9 +2,7 @@
|
|||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
@ -17,7 +15,6 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents;
|
|||
internal sealed class EditorDocument : IDisposable
|
||||
{
|
||||
private readonly IEditorDocumentManager _documentManager;
|
||||
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
|
||||
private readonly JoinableTaskContext _joinableTaskContext;
|
||||
private readonly IFileChangeTracker _fileTracker;
|
||||
private readonly SnapshotChangeTracker _snapshotTracker;
|
||||
|
@ -30,7 +27,6 @@ internal sealed class EditorDocument : IDisposable
|
|||
|
||||
public EditorDocument(
|
||||
IEditorDocumentManager documentManager,
|
||||
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
|
||||
JoinableTaskContext joinableTaskContext,
|
||||
string projectFilePath,
|
||||
string documentFilePath,
|
||||
|
@ -43,43 +39,7 @@ internal sealed class EditorDocument : IDisposable
|
|||
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;
|
||||
|
@ -97,8 +57,7 @@ internal sealed class EditorDocument : IDisposable
|
|||
// Only one of these should be active at a time.
|
||||
if (textBuffer is null)
|
||||
{
|
||||
_ = _projectSnapshotManagerDispatcher.RunAsync(
|
||||
_fileTracker.StartListening, CancellationToken.None).ConfigureAwait(false);
|
||||
_fileTracker.StartListening();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -131,8 +90,7 @@ internal sealed class EditorDocument : IDisposable
|
|||
throw new ArgumentNullException(nameof(textBuffer));
|
||||
}
|
||||
|
||||
_ = _projectSnapshotManagerDispatcher.RunAsync(
|
||||
_fileTracker.StopListening, CancellationToken.None).ConfigureAwait(false);
|
||||
_fileTracker.StopListening();
|
||||
|
||||
_snapshotTracker.StartTracking(textBuffer);
|
||||
EditorTextBuffer = textBuffer;
|
||||
|
@ -152,8 +110,7 @@ internal sealed class EditorDocument : IDisposable
|
|||
EditorTextContainer = null;
|
||||
EditorTextBuffer = null;
|
||||
|
||||
_ = _projectSnapshotManagerDispatcher.RunAsync(
|
||||
_fileTracker.StartListening, CancellationToken.None);
|
||||
_fileTracker.StartListening();
|
||||
}
|
||||
|
||||
private void ChangeTracker_Changed(object sender, FileChangeEventArgs e)
|
||||
|
@ -177,8 +134,7 @@ internal sealed class EditorDocument : IDisposable
|
|||
{
|
||||
_fileTracker.Changed -= ChangeTracker_Changed;
|
||||
|
||||
_ = _projectSnapshotManagerDispatcher.RunAsync(
|
||||
_fileTracker.StopListening, CancellationToken.None);
|
||||
_fileTracker.StopListening();
|
||||
|
||||
if (EditorTextBuffer is not null)
|
||||
{
|
||||
|
|
|
@ -23,15 +23,12 @@ internal abstract class EditorDocumentManager : IEditorDocumentManager
|
|||
|
||||
protected readonly object Lock;
|
||||
|
||||
protected ProjectSnapshotManagerDispatcher Dispatcher { get; }
|
||||
protected JoinableTaskContext JoinableTaskContext { get; }
|
||||
|
||||
protected EditorDocumentManager(
|
||||
IFileChangeTrackerFactory fileChangeTrackerFactory,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext)
|
||||
{
|
||||
Dispatcher = dispatcher;
|
||||
JoinableTaskContext = joinableTaskContext;
|
||||
_fileChangeTrackerFactory = fileChangeTrackerFactory;
|
||||
|
||||
|
@ -101,7 +98,6 @@ internal abstract class EditorDocumentManager : IEditorDocumentManager
|
|||
var textBuffer = GetTextBufferForOpenDocument(key.DocumentFilePath);
|
||||
document = new EditorDocument(
|
||||
this,
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
projectFilePath,
|
||||
key.DocumentFilePath,
|
||||
|
|
|
@ -26,8 +26,7 @@ internal sealed class VisualStudioEditorDocumentManager(
|
|||
SVsServiceProvider serviceProvider,
|
||||
IVsEditorAdaptersFactoryService editorAdaptersFactory,
|
||||
IFileChangeTrackerFactory fileChangeTrackerFactory,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext) : EditorDocumentManager(fileChangeTrackerFactory, dispatcher, joinableTaskContext)
|
||||
JoinableTaskContext joinableTaskContext) : EditorDocumentManager(fileChangeTrackerFactory, joinableTaskContext)
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider = serviceProvider;
|
||||
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactory = editorAdaptersFactory;
|
||||
|
|
|
@ -16,9 +16,10 @@ internal class VisualStudioFileChangeTracker : IFileChangeTracker, IVsFreeThread
|
|||
|
||||
private readonly IErrorReporter _errorReporter;
|
||||
private readonly IVsAsyncFileChangeEx _fileChangeService;
|
||||
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
|
||||
private readonly JoinableTaskContext _joinableTaskContext;
|
||||
|
||||
private readonly object _gate = new();
|
||||
|
||||
// Internal for testing
|
||||
internal JoinableTask<uint>? _fileChangeAdviseTask;
|
||||
internal JoinableTask? _fileChangeUnadviseTask;
|
||||
|
@ -32,7 +33,6 @@ internal class VisualStudioFileChangeTracker : IFileChangeTracker, IVsFreeThread
|
|||
string filePath,
|
||||
IErrorReporter errorReporter,
|
||||
IVsAsyncFileChangeEx fileChangeService,
|
||||
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
|
||||
JoinableTaskContext joinableTaskContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
|
@ -43,85 +43,86 @@ internal class VisualStudioFileChangeTracker : IFileChangeTracker, IVsFreeThread
|
|||
FilePath = filePath;
|
||||
_errorReporter = errorReporter;
|
||||
_fileChangeService = fileChangeService;
|
||||
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
|
||||
_joinableTaskContext = joinableTaskContext;
|
||||
}
|
||||
|
||||
public void StartListening()
|
||||
{
|
||||
_projectSnapshotManagerDispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_fileChangeAdviseTask is not null)
|
||||
lock (_gate)
|
||||
{
|
||||
// Already listening
|
||||
return;
|
||||
if (_fileChangeAdviseTask is not null)
|
||||
{
|
||||
// Already listening
|
||||
return;
|
||||
}
|
||||
|
||||
if (_fileChangeUnadviseTask is not { IsCompleted: false } fileChangeUnadviseTaskToJoin)
|
||||
{
|
||||
fileChangeUnadviseTaskToJoin = null;
|
||||
}
|
||||
|
||||
_fileChangeAdviseTask = _joinableTaskContext.Factory.RunAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// If an unadvise operation is still processing, we don't start listening until it completes.
|
||||
if (fileChangeUnadviseTaskToJoin is not null)
|
||||
await fileChangeUnadviseTaskToJoin.JoinAsync().ConfigureAwait(true);
|
||||
|
||||
return await _fileChangeService.AdviseFileChangeAsync(FilePath, FileChangeFlags, this).ConfigureAwait(true);
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
// Don't report PathTooLongExceptions but don't fault either.
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// Don't explode on actual exceptions, just report gracefully.
|
||||
_errorReporter.ReportError(exception);
|
||||
}
|
||||
|
||||
return VSConstants.VSCOOKIE_NIL;
|
||||
});
|
||||
}
|
||||
|
||||
if (_fileChangeUnadviseTask is not { IsCompleted: false } fileChangeUnadviseTaskToJoin)
|
||||
{
|
||||
fileChangeUnadviseTaskToJoin = null;
|
||||
}
|
||||
|
||||
_fileChangeAdviseTask = _joinableTaskContext.Factory.RunAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// If an unadvise operation is still processing, we don't start listening until it completes.
|
||||
if (fileChangeUnadviseTaskToJoin is not null)
|
||||
await fileChangeUnadviseTaskToJoin.JoinAsync().ConfigureAwait(true);
|
||||
|
||||
return await _fileChangeService.AdviseFileChangeAsync(FilePath, FileChangeFlags, this).ConfigureAwait(true);
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
// Don't report PathTooLongExceptions but don't fault either.
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// Don't explode on actual exceptions, just report gracefully.
|
||||
_errorReporter.ReportError(exception);
|
||||
}
|
||||
|
||||
return VSConstants.VSCOOKIE_NIL;
|
||||
});
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
_projectSnapshotManagerDispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_fileChangeAdviseTask is null || _fileChangeUnadviseTask?.IsCompleted == false)
|
||||
lock (_gate)
|
||||
{
|
||||
// Already not listening or trying to stop listening
|
||||
return;
|
||||
}
|
||||
|
||||
_fileChangeUnadviseTask = _joinableTaskContext.Factory.RunAsync(async () =>
|
||||
{
|
||||
try
|
||||
if (_fileChangeAdviseTask is null || _fileChangeUnadviseTask?.IsCompleted == false)
|
||||
{
|
||||
var fileChangeCookie = await _fileChangeAdviseTask;
|
||||
// Already not listening or trying to stop listening
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileChangeCookie == VSConstants.VSCOOKIE_NIL)
|
||||
_fileChangeUnadviseTask = _joinableTaskContext.Factory.RunAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Wasn't able to listen for file change events. This typically happens when some sort of exception (i.e. access exceptions)
|
||||
// is thrown when attempting to listen for file changes.
|
||||
return;
|
||||
}
|
||||
var fileChangeCookie = await _fileChangeAdviseTask;
|
||||
|
||||
await _fileChangeService.UnadviseFileChangeAsync(fileChangeCookie).ConfigureAwait(true);
|
||||
_fileChangeAdviseTask = null;
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
// Don't report PathTooLongExceptions but don't fault either.
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// Don't explode on actual exceptions, just report gracefully.
|
||||
_errorReporter.ReportError(exception);
|
||||
}
|
||||
});
|
||||
if (fileChangeCookie == VSConstants.VSCOOKIE_NIL)
|
||||
{
|
||||
// Wasn't able to listen for file change events. This typically happens when some sort of exception (i.e. access exceptions)
|
||||
// is thrown when attempting to listen for file changes.
|
||||
return;
|
||||
}
|
||||
|
||||
await _fileChangeService.UnadviseFileChangeAsync(fileChangeCookie).ConfigureAwait(true);
|
||||
_fileChangeAdviseTask = null;
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
// Don't report PathTooLongExceptions but don't fault either.
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// Don't explode on actual exceptions, just report gracefully.
|
||||
_errorReporter.ReportError(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public int FilesChanged(uint fileCount, string[] filePaths, uint[] fileChangeFlags)
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents;
|
|||
[Export(typeof(IFileChangeTrackerFactory))]
|
||||
internal class VisualStudioFileChangeTrackerFactory : IFileChangeTrackerFactory
|
||||
{
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
|
||||
private readonly JoinableTaskContext _joinableTaskContext;
|
||||
private readonly IErrorReporter _errorReporter;
|
||||
private readonly JoinableTask<IVsAsyncFileChangeEx> _getFileChangeServiceTask;
|
||||
|
@ -22,10 +21,8 @@ internal class VisualStudioFileChangeTrackerFactory : IFileChangeTrackerFactory
|
|||
public VisualStudioFileChangeTrackerFactory(
|
||||
[Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider,
|
||||
JoinableTaskContext joinableTaskContext,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
IErrorReporter errorReporter)
|
||||
{
|
||||
_dispatcher = dispatcher;
|
||||
_joinableTaskContext = joinableTaskContext;
|
||||
_errorReporter = errorReporter;
|
||||
|
||||
|
@ -43,6 +40,6 @@ internal class VisualStudioFileChangeTrackerFactory : IFileChangeTrackerFactory
|
|||
// TODO: Make IFileChangeTrackerFactory.Create(...) asynchronous to avoid blocking here.
|
||||
var fileChangeService = _getFileChangeServiceTask.Join();
|
||||
|
||||
return new VisualStudioFileChangeTracker(filePath, _errorReporter, fileChangeService, _dispatcher, _joinableTaskContext);
|
||||
return new VisualStudioFileChangeTracker(filePath, _errorReporter, fileChangeService, _joinableTaskContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
|
||||
|
@ -9,5 +10,5 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor;
|
|||
|
||||
internal interface IProjectWorkspaceStateGenerator
|
||||
{
|
||||
void Update(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken);
|
||||
Task UpdateAsync(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
CollaborationSession sessionContext,
|
||||
IProjectSnapshotManagerProxy hostProjectManagerProxy,
|
||||
IProjectSnapshotManager projectManager,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
IErrorReporter errorReporter,
|
||||
JoinableTaskFactory jtf) : ICollaborationService, IAsyncDisposable, System.IAsyncDisposable
|
||||
{
|
||||
|
@ -25,7 +24,6 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
private readonly IProjectSnapshotManagerProxy _hostProjectManagerProxy = hostProjectManagerProxy;
|
||||
private readonly IProjectSnapshotManager _projectManager = projectManager;
|
||||
private readonly IErrorReporter _errorReporter = errorReporter;
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
|
||||
|
||||
public async Task InitializeAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -42,22 +40,27 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
{
|
||||
_hostProjectManagerProxy.Changed -= HostProxyProjectManager_Changed;
|
||||
|
||||
await _dispatcher.Scheduler;
|
||||
|
||||
var projects = _projectManager.GetProjects();
|
||||
foreach (var project in projects)
|
||||
{
|
||||
try
|
||||
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, state) =>
|
||||
{
|
||||
_projectManager.Update(
|
||||
static (updater, key) => updater.ProjectRemoved(key),
|
||||
state: project.Key);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorReporter.ReportError(ex, project);
|
||||
}
|
||||
}
|
||||
var (projects, errorReporter) = state;
|
||||
|
||||
foreach (var project in projects)
|
||||
{
|
||||
try
|
||||
{
|
||||
updater.ProjectRemoved(project.Key);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorReporter.ReportError(ex, project);
|
||||
}
|
||||
}
|
||||
},
|
||||
state: (projects, _errorReporter),
|
||||
CancellationToken.None);
|
||||
}
|
||||
|
||||
ValueTask System.IAsyncDisposable.DisposeAsync()
|
||||
|
@ -68,15 +71,13 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
// Internal for testing
|
||||
internal async ValueTask UpdateGuestProjectManagerAsync(ProjectChangeEventProxyArgs args)
|
||||
{
|
||||
await _dispatcher.Scheduler;
|
||||
|
||||
if (args.Kind == ProjectProxyChangeKind.ProjectAdded)
|
||||
{
|
||||
var guestPath = ResolveGuestPath(args.ProjectFilePath);
|
||||
var guestIntermediateOutputPath = ResolveGuestPath(args.IntermediateOutputPath);
|
||||
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, args.Newer!.Configuration, args.Newer.RootNamespace);
|
||||
|
||||
_projectManager.Update(
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, state) =>
|
||||
{
|
||||
updater.ProjectAdded(state.hostProject);
|
||||
|
@ -86,12 +87,13 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
updater.ProjectWorkspaceStateChanged(state.hostProject.Key, state.projectWorkspaceState);
|
||||
}
|
||||
},
|
||||
state: (hostProject, projectWorkspaceState: args.Newer.ProjectWorkspaceState));
|
||||
state: (hostProject, projectWorkspaceState: args.Newer.ProjectWorkspaceState),
|
||||
CancellationToken.None);
|
||||
}
|
||||
else if (args.Kind == ProjectProxyChangeKind.ProjectRemoved)
|
||||
{
|
||||
var guestPath = ResolveGuestPath(args.ProjectFilePath);
|
||||
_projectManager.Update(
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, guestPath) =>
|
||||
{
|
||||
var projectKeys = updater.GetAllProjectKeys(guestPath);
|
||||
|
@ -100,7 +102,8 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
updater.ProjectRemoved(projectKey);
|
||||
}
|
||||
},
|
||||
state: guestPath);
|
||||
state: guestPath,
|
||||
CancellationToken.None);
|
||||
}
|
||||
else if (args.Kind == ProjectProxyChangeKind.ProjectChanged)
|
||||
{
|
||||
|
@ -109,15 +112,16 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
var guestPath = ResolveGuestPath(args.Newer.FilePath);
|
||||
var guestIntermediateOutputPath = ResolveGuestPath(args.Newer.IntermediateOutputPath);
|
||||
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, args.Newer.Configuration, args.Newer.RootNamespace);
|
||||
_projectManager.Update(
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, hostProject) => updater.ProjectConfigurationChanged(hostProject),
|
||||
state: hostProject);
|
||||
state: hostProject,
|
||||
CancellationToken.None);
|
||||
}
|
||||
else if (args.Older.ProjectWorkspaceState != args.Newer.ProjectWorkspaceState ||
|
||||
args.Older.ProjectWorkspaceState?.Equals(args.Newer.ProjectWorkspaceState) == false)
|
||||
{
|
||||
var guestPath = ResolveGuestPath(args.Newer.FilePath);
|
||||
_projectManager.Update(
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, state) =>
|
||||
{
|
||||
var projectKeys = updater.GetAllProjectKeys(state.guestPath);
|
||||
|
@ -127,21 +131,20 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
updater.ProjectWorkspaceStateChanged(projectKey, state.projectWorkspaceState);
|
||||
}
|
||||
},
|
||||
state: (guestPath, projectWorkspaceState: args.Newer.ProjectWorkspaceState));
|
||||
state: (guestPath, projectWorkspaceState: args.Newer.ProjectWorkspaceState),
|
||||
CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeGuestProjectManagerAsync(IReadOnlyList<ProjectSnapshotHandleProxy> projectHandles)
|
||||
{
|
||||
await _dispatcher.Scheduler;
|
||||
|
||||
foreach (var projectHandle in projectHandles)
|
||||
{
|
||||
var guestPath = ResolveGuestPath(projectHandle.FilePath);
|
||||
var guestIntermediateOutputPath = ResolveGuestPath(projectHandle.IntermediateOutputPath);
|
||||
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, projectHandle.Configuration, projectHandle.RootNamespace);
|
||||
_projectManager.Update(
|
||||
await _projectManager.UpdateAsync(
|
||||
static (updater, state) =>
|
||||
{
|
||||
updater.ProjectAdded(state.hostProject);
|
||||
|
@ -151,7 +154,8 @@ internal class ProjectSnapshotSynchronizationService(
|
|||
updater.ProjectWorkspaceStateChanged(state.hostProject.Key, state.projectWorkspaceState);
|
||||
}
|
||||
},
|
||||
state: (hostProject, projectWorkspaceState: projectHandle.ProjectWorkspaceState));
|
||||
state: (hostProject, projectWorkspaceState: projectHandle.ProjectWorkspaceState),
|
||||
CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Guest;
|
|||
[method: ImportingConstructor]
|
||||
internal class ProjectSnapshotSynchronizationServiceFactory(
|
||||
IProjectSnapshotManager projectManager,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
IErrorReporter errorReporter,
|
||||
JoinableTaskContext joinableTaskContext) : ICollaborationServiceFactory
|
||||
{
|
||||
|
@ -32,7 +31,6 @@ internal class ProjectSnapshotSynchronizationServiceFactory(
|
|||
sessionContext,
|
||||
projectSnapshotManagerProxy,
|
||||
projectManager,
|
||||
dispatcher,
|
||||
errorReporter,
|
||||
joinableTaskContext.Factory);
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
|
||||
|
@ -16,7 +15,6 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host;
|
|||
internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, ICollaborationService, IDisposable
|
||||
{
|
||||
private readonly CollaborationSession _session;
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
|
||||
private readonly IProjectSnapshotManager _projectSnapshotManager;
|
||||
private readonly JoinableTaskFactory _jtf;
|
||||
private readonly AsyncSemaphore _latestStateSemaphore;
|
||||
|
@ -28,11 +26,9 @@ internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, IColl
|
|||
public ProjectSnapshotManagerProxy(
|
||||
CollaborationSession session,
|
||||
IProjectSnapshotManager projectSnapshotManager,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskFactory jtf)
|
||||
{
|
||||
_session = session;
|
||||
_dispatcher = dispatcher;
|
||||
_projectSnapshotManager = projectSnapshotManager;
|
||||
_jtf = jtf;
|
||||
|
||||
|
@ -110,8 +106,6 @@ internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, IColl
|
|||
|
||||
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args)
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
using System.ComponentModel.Composition;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.LiveShare.Razor.Serialization;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
|
@ -20,7 +19,6 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host;
|
|||
[method: ImportingConstructor]
|
||||
internal class ProjectSnapshotManagerProxyFactory(
|
||||
IProjectSnapshotManager projectManager,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext) : ICollaborationServiceFactory
|
||||
{
|
||||
public Task<ICollaborationService> CreateServiceAsync(CollaborationSession session, CancellationToken cancellationToken)
|
||||
|
@ -29,7 +27,7 @@ internal class ProjectSnapshotManagerProxyFactory(
|
|||
serializer.Converters.RegisterRazorLiveShareConverters();
|
||||
|
||||
var service = new ProjectSnapshotManagerProxy(
|
||||
session, projectManager, dispatcher, joinableTaskContext.Factory);
|
||||
session, projectManager, joinableTaskContext.Factory);
|
||||
return Task.FromResult<ICollaborationService>(service);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,40 +46,43 @@ internal sealed class ProjectWorkspaceStateGenerator(
|
|||
// Used in unit tests to ensure we can know when background work finishes.
|
||||
public ManualResetEventSlim? NotifyBackgroundWorkCompleted { get; set; }
|
||||
|
||||
public void Update(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
|
||||
public Task UpdateAsync(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
|
||||
{
|
||||
if (projectSnapshot is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectSnapshot));
|
||||
}
|
||||
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
return _dispatcher.RunAsync(
|
||||
() =>
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Updates.TryGetValue(projectSnapshot.Key, out var updateItem) &&
|
||||
!updateItem.Task.IsCompleted &&
|
||||
!updateItem.Cts.IsCancellationRequested)
|
||||
{
|
||||
updateItem.Cts.Cancel();
|
||||
}
|
||||
|
||||
if (Updates.TryGetValue(projectSnapshot.Key, out var updateItem) &&
|
||||
!updateItem.Task.IsCompleted &&
|
||||
!updateItem.Cts.IsCancellationRequested)
|
||||
{
|
||||
updateItem.Cts.Cancel();
|
||||
}
|
||||
if (updateItem?.Cts.IsCancellationRequested == false)
|
||||
{
|
||||
updateItem?.Cts.Dispose();
|
||||
}
|
||||
|
||||
if (updateItem?.Cts.IsCancellationRequested == false)
|
||||
{
|
||||
updateItem?.Cts.Dispose();
|
||||
}
|
||||
|
||||
var lcts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
var updateTask = Task.Factory.StartNew(
|
||||
() => UpdateWorkspaceStateAsync(workspaceProject, projectSnapshot, lcts.Token),
|
||||
lcts.Token,
|
||||
TaskCreationOptions.None,
|
||||
TaskScheduler.Default).Unwrap();
|
||||
updateItem = new UpdateItem(updateTask, lcts);
|
||||
Updates[projectSnapshot.Key] = updateItem;
|
||||
var lcts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
var updateTask = Task.Factory.StartNew(
|
||||
() => UpdateWorkspaceStateAsync(workspaceProject, projectSnapshot, lcts.Token),
|
||||
lcts.Token,
|
||||
TaskCreationOptions.None,
|
||||
TaskScheduler.Default).Unwrap();
|
||||
updateItem = new UpdateItem(updateTask, lcts);
|
||||
Updates[projectSnapshot.Key] = updateItem;
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Razor.Workspaces;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
|
@ -25,7 +24,6 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
|
|||
private readonly IProjectSnapshotManager _projectManager;
|
||||
private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator;
|
||||
private readonly IWorkspaceProvider _workspaceProvider;
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
|
||||
private readonly JoinableTaskFactory _jtf;
|
||||
private readonly JoinableTask _initializeTask;
|
||||
|
||||
|
@ -41,14 +39,12 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
|
|||
IProjectSnapshotManager projectManager,
|
||||
IProjectWorkspaceStateGenerator workspaceStateGenerator,
|
||||
IWorkspaceProvider workspaceProvider,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_projectManager = projectManager;
|
||||
_workspaceStateGenerator = workspaceStateGenerator;
|
||||
_workspaceProvider = workspaceProvider;
|
||||
_dispatcher = dispatcher;
|
||||
_jtf = joinableTaskContext.Factory;
|
||||
|
||||
_projectManager.Changed += ProjectManager_Changed;
|
||||
|
@ -127,29 +123,26 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
|
|||
return;
|
||||
}
|
||||
|
||||
await _dispatcher.RunAsync(() =>
|
||||
if (_projectManager is null)
|
||||
{
|
||||
if (_projectManager is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var projectKeys = _projectManager.GetAllProjectKeys(projectFilePath);
|
||||
foreach (var projectKey in projectKeys)
|
||||
var projectKeys = _projectManager.GetAllProjectKeys(projectFilePath);
|
||||
foreach (var projectKey in projectKeys)
|
||||
{
|
||||
if (_projectManager.TryGetLoadedProject(projectKey, out var projectSnapshot))
|
||||
{
|
||||
if (_projectManager.TryGetLoadedProject(projectKey, out var projectSnapshot))
|
||||
var workspace = _workspaceProvider.GetWorkspace();
|
||||
var workspaceProject = workspace.CurrentSolution.Projects.FirstOrDefault(wp => ProjectKey.From(wp) == projectSnapshot.Key);
|
||||
if (workspaceProject is not null)
|
||||
{
|
||||
var workspace = _workspaceProvider.GetWorkspace();
|
||||
var workspaceProject = workspace.CurrentSolution.Projects.FirstOrDefault(wp => ProjectKey.From(wp) == projectSnapshot.Key);
|
||||
if (workspaceProject is not 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);
|
||||
}
|
||||
// Trigger a tag helper update by forcing the project manager to see the workspace Project
|
||||
// from the current solution.
|
||||
await _workspaceStateGenerator.UpdateAsync(workspaceProject, projectSnapshot, cancellationToken);
|
||||
}
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal TestAccessor GetTestAccessor() => new(this);
|
||||
|
|
|
@ -28,7 +28,6 @@ internal partial class WorkspaceProjectStateChangeDetector : IRazorStartupServic
|
|||
private readonly IProjectSnapshotManager _projectManager;
|
||||
private readonly LanguageServerFeatureOptions _options;
|
||||
private readonly Workspace _workspace;
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
|
||||
|
||||
private readonly CancellationTokenSource _disposeTokenSource;
|
||||
private readonly AsyncBatchingWorkQueue<(Project?, IProjectSnapshot)> _workQueue;
|
||||
|
@ -40,13 +39,11 @@ internal partial class WorkspaceProjectStateChangeDetector : IRazorStartupServic
|
|||
IProjectWorkspaceStateGenerator generator,
|
||||
IProjectSnapshotManager projectManager,
|
||||
LanguageServerFeatureOptions options,
|
||||
IWorkspaceProvider workspaceProvider,
|
||||
ProjectSnapshotManagerDispatcher dispatcher)
|
||||
IWorkspaceProvider workspaceProvider)
|
||||
{
|
||||
_generator = generator;
|
||||
_projectManager = projectManager;
|
||||
_options = options;
|
||||
_dispatcher = dispatcher;
|
||||
|
||||
_disposeTokenSource = new();
|
||||
_workQueue = new AsyncBatchingWorkQueue<(Project?, IProjectSnapshot)>(
|
||||
|
@ -82,14 +79,7 @@ internal partial class WorkspaceProjectStateChangeDetector : IRazorStartupServic
|
|||
return;
|
||||
}
|
||||
|
||||
await _dispatcher.RunAsync(
|
||||
static state =>
|
||||
{
|
||||
var (generator, project, projectSnapshot, token) = state;
|
||||
generator.Update(project, projectSnapshot, token);
|
||||
},
|
||||
state: (_generator, project, projectSnapshot, token),
|
||||
token);
|
||||
await _generator.UpdateAsync(project, projectSnapshot, token);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Completion;
|
||||
using Microsoft.CodeAnalysis.Razor.Tooltip;
|
||||
using Microsoft.VisualStudio.Core.Imaging;
|
||||
|
@ -44,17 +43,14 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
|
|||
private readonly ICompletionBroker _completionBroker;
|
||||
private readonly IVisualStudioDescriptionFactory _descriptionFactory;
|
||||
private readonly JoinableTaskFactory _joinableTaskFactory;
|
||||
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
|
||||
|
||||
public RazorDirectiveAttributeCompletionSource(
|
||||
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
|
||||
IVisualStudioRazorParser parser,
|
||||
IRazorCompletionFactsService completionFactsService,
|
||||
ICompletionBroker completionBroker,
|
||||
IVisualStudioDescriptionFactory descriptionFactory,
|
||||
JoinableTaskFactory joinableTaskFactory)
|
||||
{
|
||||
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
|
||||
_parser = parser ?? throw new ArgumentNullException(nameof(parser));
|
||||
_completionFactsService = completionFactsService ?? throw new ArgumentNullException(nameof(completionFactsService));
|
||||
_completionBroker = completionBroker;
|
||||
|
|
|
@ -23,13 +23,11 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor.Completion;
|
|||
[ContentType(RazorConstants.LegacyCoreContentType)]
|
||||
[method: ImportingConstructor]
|
||||
internal sealed class RazorDirectiveAttributeCompletionSourceProvider(
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
IRazorCompletionFactsService completionFactsService,
|
||||
ICompletionBroker completionBroker,
|
||||
IVisualStudioDescriptionFactory descriptionFactory,
|
||||
JoinableTaskContext joinableTaskContext) : IAsyncCompletionSourceProvider
|
||||
{
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
|
||||
private readonly IRazorCompletionFactsService _completionFactsService = completionFactsService;
|
||||
private readonly ICompletionBroker _completionBroker = completionBroker;
|
||||
private readonly IVisualStudioDescriptionFactory _descriptionFactory = descriptionFactory;
|
||||
|
@ -63,7 +61,6 @@ internal sealed class RazorDirectiveAttributeCompletionSourceProvider(
|
|||
}
|
||||
|
||||
return new RazorDirectiveAttributeCompletionSource(
|
||||
_dispatcher,
|
||||
parser,
|
||||
_completionFactsService,
|
||||
_completionBroker,
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.VisualStudio.Editor.Razor.Documents;
|
||||
|
||||
namespace Microsoft.VisualStudio.LegacyEditor.Razor;
|
||||
|
||||
internal class ImportChangedEventArgs(string filePath, FileChangeKind kind, IEnumerable<string> associatedDocuments) : EventArgs
|
||||
internal class ImportChangedEventArgs(string filePath, FileChangeKind kind, ImmutableArray<string> associatedDocuments) : EventArgs
|
||||
{
|
||||
public string FilePath => filePath;
|
||||
public FileChangeKind Kind => kind;
|
||||
public IEnumerable<string> AssociatedDocuments => associatedDocuments;
|
||||
public ImmutableArray<string> AssociatedDocuments => associatedDocuments;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Editor.Razor.Documents;
|
||||
|
||||
|
@ -15,12 +15,11 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor;
|
|||
|
||||
[Export(typeof(IImportDocumentManager))]
|
||||
[method: ImportingConstructor]
|
||||
internal sealed class ImportDocumentManager(
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
IFileChangeTrackerFactory fileChangeTrackerFactory) : IImportDocumentManager
|
||||
internal sealed class ImportDocumentManager(IFileChangeTrackerFactory fileChangeTrackerFactory) : IImportDocumentManager
|
||||
{
|
||||
private readonly IFileChangeTrackerFactory _fileChangeTrackerFactory = fileChangeTrackerFactory;
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
|
||||
|
||||
private readonly object _gate = new();
|
||||
private readonly Dictionary<string, ImportTracker> _importTrackerCache = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public event EventHandler<ImportChangedEventArgs>? Changed;
|
||||
|
@ -32,8 +31,6 @@ internal sealed class ImportDocumentManager(
|
|||
throw new ArgumentNullException(nameof(documentTracker));
|
||||
}
|
||||
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
var filePath = documentTracker.FilePath;
|
||||
var projectSnapshot = documentTracker.ProjectSnapshot.AssumeNotNull();
|
||||
|
||||
|
@ -48,18 +45,21 @@ internal sealed class ImportDocumentManager(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
|
||||
lock (_gate)
|
||||
{
|
||||
// First time seeing this import. Start tracking it.
|
||||
var fileChangeTracker = _fileChangeTrackerFactory.Create(importFilePath);
|
||||
importTracker = new ImportTracker(fileChangeTracker);
|
||||
_importTrackerCache[importFilePath] = importTracker;
|
||||
if (!_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
|
||||
{
|
||||
// First time seeing this import. Start tracking it.
|
||||
var fileChangeTracker = _fileChangeTrackerFactory.Create(importFilePath);
|
||||
importTracker = new ImportTracker(fileChangeTracker);
|
||||
_importTrackerCache[importFilePath] = importTracker;
|
||||
|
||||
fileChangeTracker.Changed += FileChangeTracker_Changed;
|
||||
fileChangeTracker.StartListening();
|
||||
fileChangeTracker.Changed += FileChangeTracker_Changed;
|
||||
fileChangeTracker.StartListening();
|
||||
}
|
||||
|
||||
importTracker.AddAssociatedDocument(documentTracker.FilePath);
|
||||
}
|
||||
|
||||
importTracker.AssociatedDocuments.Add(documentTracker.FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,6 @@ internal sealed class ImportDocumentManager(
|
|||
throw new ArgumentNullException(nameof(documentTracker));
|
||||
}
|
||||
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
var filePath = documentTracker.FilePath;
|
||||
var projectSnapshot = documentTracker.ProjectSnapshot.AssumeNotNull();
|
||||
|
||||
|
@ -79,15 +77,18 @@ internal sealed class ImportDocumentManager(
|
|||
{
|
||||
var importPhysicalPath = import.PhysicalPath.AssumeNotNull();
|
||||
|
||||
if (_importTrackerCache.TryGetValue(importPhysicalPath, out var importTracker))
|
||||
lock (_gate)
|
||||
{
|
||||
importTracker.AssociatedDocuments.Remove(documentTracker.FilePath);
|
||||
|
||||
if (importTracker.AssociatedDocuments.Count == 0)
|
||||
if (_importTrackerCache.TryGetValue(importPhysicalPath, out var importTracker))
|
||||
{
|
||||
// There are no open documents that care about this import. We no longer need to track it.
|
||||
importTracker.FileChangeTracker.StopListening();
|
||||
_importTrackerCache.Remove(importPhysicalPath);
|
||||
importTracker.RemoveAssociatedDocument(documentTracker.FilePath);
|
||||
|
||||
if (importTracker.AssociatedDocumentCount == 0)
|
||||
{
|
||||
// There are no open documents that care about this import. We no longer need to track it.
|
||||
importTracker.FileChangeTracker.StopListening();
|
||||
_importTrackerCache.Remove(importPhysicalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,18 +121,31 @@ internal sealed class ImportDocumentManager(
|
|||
|
||||
private void FileChangeTracker_Changed(object sender, FileChangeEventArgs args)
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_importTrackerCache.TryGetValue(args.FilePath, out var importTracker))
|
||||
lock (_gate)
|
||||
{
|
||||
Changed?.Invoke(this, new ImportChangedEventArgs(importTracker.FilePath, args.Kind, importTracker.AssociatedDocuments));
|
||||
if (_importTrackerCache.TryGetValue(args.FilePath, out var importTracker))
|
||||
{
|
||||
Changed?.Invoke(this, new ImportChangedEventArgs(importTracker.FilePath, args.Kind, importTracker.GetAssociatedDocuments()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ImportTracker(IFileChangeTracker fileChangeTracker)
|
||||
{
|
||||
private readonly HashSet<string> _associatedDocuments = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public IFileChangeTracker FileChangeTracker => fileChangeTracker;
|
||||
public string FilePath => fileChangeTracker.FilePath;
|
||||
public HashSet<string> AssociatedDocuments { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public int AssociatedDocumentCount => _associatedDocuments.Count;
|
||||
|
||||
public void AddAssociatedDocument(string filePath)
|
||||
=> _associatedDocuments.Add(filePath);
|
||||
|
||||
public void RemoveAssociatedDocument(string filePath)
|
||||
=> _associatedDocuments.Remove(filePath);
|
||||
|
||||
public ImmutableArray<string> GetAssociatedDocuments()
|
||||
=> _associatedDocuments.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
|
@ -17,10 +15,8 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor;
|
|||
[method: ImportingConstructor]
|
||||
internal sealed class RazorDocumentManager(
|
||||
IRazorEditorFactoryService editorFactoryService,
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext) : IRazorDocumentManager
|
||||
{
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
|
||||
private readonly JoinableTaskFactory _jtf = joinableTaskContext.Factory;
|
||||
private readonly IRazorEditorFactoryService _editorFactoryService = editorFactoryService;
|
||||
|
||||
|
@ -46,9 +42,7 @@ internal sealed class RazorDocumentManager(
|
|||
|
||||
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 _dispatcher.RunAsync(() => tracker.Subscribe(), CancellationToken.None).ConfigureAwait(false);
|
||||
tracker.Subscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,9 +64,7 @@ internal sealed class RazorDocumentManager(
|
|||
|
||||
if (documentTracker.TextViews.Count == 0)
|
||||
{
|
||||
// tracker.Unsubscribe() should be in sync with tracker.Subscribe(). The latter of needs to be run
|
||||
// on the project snapshot manager's specialized thread, so we run both on it.
|
||||
await _dispatcher.RunAsync(() => documentTracker.Unsubscribe(), CancellationToken.None).ConfigureAwait(false);
|
||||
documentTracker.Unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Razor.Settings;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
|
@ -22,7 +22,6 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor;
|
|||
|
||||
internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
||||
{
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
|
||||
private readonly JoinableTaskContext _joinableTaskContext;
|
||||
private readonly string _filePath;
|
||||
private readonly string _projectPath;
|
||||
|
@ -34,12 +33,12 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
|
||||
private bool _isSupportedProject;
|
||||
private IProjectSnapshot? _projectSnapshot;
|
||||
|
||||
private int _subscribeCount;
|
||||
|
||||
public event EventHandler<ContextChangeEventArgs>? ContextChanged;
|
||||
|
||||
public VisualStudioDocumentTracker(
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext,
|
||||
string filePath,
|
||||
string projectPath,
|
||||
|
@ -54,7 +53,6 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
throw new ArgumentException(SR.ArgumentCannotBeNullOrEmpty, nameof(filePath));
|
||||
}
|
||||
|
||||
_dispatcher = dispatcher;
|
||||
_joinableTaskContext = joinableTaskContext;
|
||||
_filePath = filePath;
|
||||
_projectPath = projectPath;
|
||||
|
@ -143,9 +141,7 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
|
||||
public void Subscribe()
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_subscribeCount++ > 0)
|
||||
if (Interlocked.Increment(ref _subscribeCount) != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -164,8 +160,6 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
|
||||
private IProjectSnapshot GetOrCreateProject(string projectPath)
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
var projectKeys = _projectManager.GetAllProjectKeys(projectPath);
|
||||
|
||||
if (projectKeys.Length == 0 ||
|
||||
|
@ -179,9 +173,7 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
|
||||
public void Unsubscribe()
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_subscribeCount == 0 || _subscribeCount-- > 1)
|
||||
if (Interlocked.Decrement(ref _subscribeCount) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -214,8 +206,6 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
return;
|
||||
}
|
||||
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
if (_projectPath is not null &&
|
||||
string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -268,8 +258,6 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker
|
|||
// Internal for testing
|
||||
internal void Import_Changed(object sender, ImportChangedEventArgs args)
|
||||
{
|
||||
_dispatcher.AssertRunningOnDispatcher();
|
||||
|
||||
foreach (var path in args.AssociatedDocuments)
|
||||
{
|
||||
if (string.Equals(_filePath, path, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.LegacyEditor.Razor.Settings;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
@ -16,7 +15,6 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor;
|
|||
[Export(typeof(IVisualStudioDocumentTrackerFactory))]
|
||||
[method: ImportingConstructor]
|
||||
internal sealed class VisualStudioDocumentTrackerFactory(
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext,
|
||||
IProjectSnapshotManager projectManager,
|
||||
IWorkspaceEditorSettings workspaceEditorSettings,
|
||||
|
@ -25,7 +23,6 @@ internal sealed class VisualStudioDocumentTrackerFactory(
|
|||
IImportDocumentManager importDocumentManager,
|
||||
IProjectEngineFactoryProvider projectEngineFactoryProvider) : IVisualStudioDocumentTrackerFactory
|
||||
{
|
||||
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
|
||||
private readonly JoinableTaskContext _joinableTaskContext = joinableTaskContext;
|
||||
private readonly ITextDocumentFactoryService _textDocumentFactory = textDocumentFactory;
|
||||
private readonly IProjectPathProvider _projectPathProvider = projectPathProvider;
|
||||
|
@ -54,7 +51,7 @@ internal sealed class VisualStudioDocumentTrackerFactory(
|
|||
|
||||
var filePath = textDocument.FilePath;
|
||||
var tracker = new VisualStudioDocumentTracker(
|
||||
_dispatcher, _joinableTaskContext, filePath, projectPath, _projectManager, _workspaceEditorSettings, _projectEngineFactoryProvider, textBuffer, _importDocumentManager);
|
||||
_joinableTaskContext, filePath, projectPath, _projectManager, _workspaceEditorSettings, _projectEngineFactoryProvider, textBuffer, _importDocumentManager);
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
|
|
@ -192,8 +192,14 @@ public class EditorDocumentManagerListenerTest(ITestOutputHelper testOutput) : V
|
|||
|
||||
private EditorDocument GetEditorDocument(bool isOpen = false, IEditorDocumentManager? documentManager = null)
|
||||
{
|
||||
var fileChangeTracker = StrictMock.Of<IFileChangeTracker>(x =>
|
||||
x.FilePath == s_hostDocument.FilePath);
|
||||
var fileChangeTrackerMock = new StrictMock<IFileChangeTracker>();
|
||||
fileChangeTrackerMock
|
||||
.SetupGet(x => x.FilePath)
|
||||
.Returns(s_hostDocument.FilePath);
|
||||
fileChangeTrackerMock
|
||||
.Setup(x => x.StartListening());
|
||||
fileChangeTrackerMock
|
||||
.Setup(x => x.StopListening());
|
||||
|
||||
var textBuffer = isOpen
|
||||
? new TestTextBuffer(new StringTextSnapshot("Hello"))
|
||||
|
@ -201,13 +207,12 @@ public class EditorDocumentManagerListenerTest(ITestOutputHelper testOutput) : V
|
|||
|
||||
return new EditorDocument(
|
||||
documentManager ?? StrictMock.Of<IEditorDocumentManager>(),
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
s_hostProject.FilePath,
|
||||
s_hostDocument.FilePath,
|
||||
s_hostProject.Key,
|
||||
StrictMock.Of<TextLoader>(),
|
||||
fileChangeTracker,
|
||||
fileChangeTrackerMock.Object,
|
||||
textBuffer,
|
||||
changedOnDisk: null,
|
||||
changedInEditor: null,
|
||||
|
|
|
@ -30,7 +30,7 @@ public class EditorDocumentManagerTest : VisualStudioTestBase
|
|||
public EditorDocumentManagerTest(ITestOutputHelper testOutput)
|
||||
: base(testOutput)
|
||||
{
|
||||
_manager = new TestEditorDocumentManager(Dispatcher, JoinableTaskFactory.Context);
|
||||
_manager = new TestEditorDocumentManager(JoinableTaskFactory.Context);
|
||||
_projectKey1 = TestProjectData.SomeProject.Key;
|
||||
_projectKey2 = TestProjectData.AnotherProject.Key;
|
||||
_projectFile1 = TestProjectData.SomeProject.FilePath;
|
||||
|
@ -179,9 +179,8 @@ public class EditorDocumentManagerTest : VisualStudioTestBase
|
|||
}
|
||||
|
||||
private class TestEditorDocumentManager(
|
||||
ProjectSnapshotManagerDispatcher dispatcher,
|
||||
JoinableTaskContext joinableTaskContext)
|
||||
: EditorDocumentManager(CreateFileChangeTrackerFactory(), dispatcher, joinableTaskContext)
|
||||
: EditorDocumentManager(CreateFileChangeTrackerFactory(), joinableTaskContext)
|
||||
{
|
||||
public List<EditorDocument> Opened { get; } = new List<EditorDocument>();
|
||||
|
||||
|
@ -191,10 +190,19 @@ public class EditorDocumentManagerTest : VisualStudioTestBase
|
|||
|
||||
private static IFileChangeTrackerFactory CreateFileChangeTrackerFactory()
|
||||
{
|
||||
var mock = new Mock<IFileChangeTrackerFactory>(MockBehavior.Strict);
|
||||
var mock = new StrictMock<IFileChangeTrackerFactory>();
|
||||
|
||||
mock.Setup(x => x.Create(It.IsAny<string>()))
|
||||
.Returns((string filePath) => Mock.Of<IFileChangeTracker>(x => x.FilePath == filePath, MockBehavior.Strict));
|
||||
.Returns((string filePath) =>
|
||||
{
|
||||
var mock = new StrictMock<IFileChangeTracker>();
|
||||
mock.SetupGet(x => x.FilePath)
|
||||
.Returns(filePath);
|
||||
mock.Setup(x => x.StartListening());
|
||||
mock.Setup(x => x.StopListening());
|
||||
|
||||
return mock.Object;
|
||||
});
|
||||
|
||||
return mock.Object;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,23 @@ public class EditorDocumentTest : VisualStudioTestBase
|
|||
public EditorDocumentTest(ITestOutputHelper testOutput)
|
||||
: base(testOutput)
|
||||
{
|
||||
_documentManager = new Mock<IEditorDocumentManager>(MockBehavior.Strict).Object;
|
||||
Mock.Get(_documentManager).Setup(m => m.RemoveDocument(It.IsAny<EditorDocument>())).Verifiable();
|
||||
_documentManager = StrictMock.Of<IEditorDocumentManager>();
|
||||
Mock.Get(_documentManager)
|
||||
.Setup(m => m.RemoveDocument(It.IsAny<EditorDocument>()))
|
||||
.Verifiable();
|
||||
|
||||
_projectFilePath = TestProjectData.SomeProject.FilePath;
|
||||
_projectKey = TestProjectData.SomeProject.Key;
|
||||
_documentFilePath = TestProjectData.SomeProjectFile1.FilePath;
|
||||
_textLoader = TextLoader.From(TextAndVersion.Create(SourceText.From("FILE"), VersionStamp.Default));
|
||||
_fileChangeTracker = Mock.Of<IFileChangeTracker>(x => x.FilePath == _documentFilePath, MockBehavior.Strict);
|
||||
|
||||
var mock = new StrictMock<IFileChangeTracker>();
|
||||
mock.SetupGet(x => x.FilePath)
|
||||
.Returns(_documentFilePath);
|
||||
mock.Setup(x => x.StartListening());
|
||||
mock.Setup(x => x.StopListening());
|
||||
|
||||
_fileChangeTracker = mock.Object;
|
||||
|
||||
_textBuffer = new TestTextBuffer(new StringTextSnapshot("Hello"));
|
||||
}
|
||||
|
@ -43,7 +53,6 @@ public class EditorDocumentTest : VisualStudioTestBase
|
|||
// Arrange & Act
|
||||
using var document = new EditorDocument(
|
||||
_documentManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context,
|
||||
_projectFilePath,
|
||||
_documentFilePath,
|
||||
|
@ -68,7 +77,6 @@ public class EditorDocumentTest : VisualStudioTestBase
|
|||
// Arrange & Act
|
||||
using var document = new EditorDocument(
|
||||
_documentManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context,
|
||||
_projectFilePath,
|
||||
_documentFilePath,
|
||||
|
|
|
@ -30,11 +30,10 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
TestProjectData.SomeProjectImportFile.FilePath,
|
||||
ErrorReporter,
|
||||
fileChangeService.Object,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context);
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(tracker.StartListening);
|
||||
tracker.StartListening();
|
||||
|
||||
await tracker._fileChangeAdviseTask!;
|
||||
|
||||
|
@ -56,13 +55,12 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
TestProjectData.SomeProjectImportFile.FilePath,
|
||||
ErrorReporter,
|
||||
fileChangeService.Object,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context);
|
||||
|
||||
await RunOnDispatcherAsync(tracker.StartListening);
|
||||
tracker.StartListening();
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(tracker.StartListening);
|
||||
tracker.StartListening();
|
||||
|
||||
await tracker._fileChangeAdviseTask!;
|
||||
|
||||
|
@ -86,15 +84,14 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
TestProjectData.SomeProjectImportFile.FilePath,
|
||||
ErrorReporter,
|
||||
fileChangeService.Object,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context);
|
||||
|
||||
await RunOnDispatcherAsync(tracker.StartListening);
|
||||
tracker.StartListening();
|
||||
|
||||
await tracker._fileChangeAdviseTask!;
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(tracker.StopListening);
|
||||
tracker.StopListening();
|
||||
|
||||
await tracker._fileChangeUnadviseTask!;
|
||||
|
||||
|
@ -103,7 +100,7 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task StopListening_NotListening_DoesNothing()
|
||||
public void StopListening_NotListening_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var fileChangeService = new StrictMock<IVsAsyncFileChangeEx>();
|
||||
|
@ -114,11 +111,10 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
TestProjectData.SomeProjectImportFile.FilePath,
|
||||
ErrorReporter,
|
||||
fileChangeService.Object,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context);
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(tracker.StopListening);
|
||||
tracker.StopListening();
|
||||
|
||||
// Assert
|
||||
Assert.Null(tracker._fileChangeUnadviseTask);
|
||||
|
@ -134,7 +130,7 @@ public class VisualStudioFileChangeTrackerTest(ITestOutputHelper testOutput) : V
|
|||
// Arrange
|
||||
var filePath = TestProjectData.SomeProjectImportFile.FilePath;
|
||||
var fileChangeService = Mock.Of<IVsAsyncFileChangeEx>(MockBehavior.Strict);
|
||||
var tracker = new VisualStudioFileChangeTracker(filePath, ErrorReporter, fileChangeService, Dispatcher, JoinableTaskFactory.Context);
|
||||
var tracker = new VisualStudioFileChangeTracker(filePath, ErrorReporter, fileChangeService, JoinableTaskFactory.Context);
|
||||
|
||||
var called = false;
|
||||
tracker.Changed += (sender, args) =>
|
||||
|
|
|
@ -54,7 +54,6 @@ public class ProjectSnapshotSynchronizationServiceTest : VisualStudioWorkspaceTe
|
|||
_sessionContext,
|
||||
hostProjectManagerProxyMock.Object,
|
||||
_projectManager,
|
||||
Dispatcher,
|
||||
ErrorReporter,
|
||||
JoinableTaskFactory);
|
||||
|
||||
|
@ -89,7 +88,6 @@ public class ProjectSnapshotSynchronizationServiceTest : VisualStudioWorkspaceTe
|
|||
_sessionContext,
|
||||
StrictMock.Of<IProjectSnapshotManagerProxy>(),
|
||||
_projectManager,
|
||||
Dispatcher,
|
||||
ErrorReporter,
|
||||
JoinableTaskFactory);
|
||||
var args = new ProjectChangeEventProxyArgs(older: null, newHandle, ProjectProxyChangeKind.ProjectAdded);
|
||||
|
@ -125,7 +123,6 @@ public class ProjectSnapshotSynchronizationServiceTest : VisualStudioWorkspaceTe
|
|||
_sessionContext,
|
||||
StrictMock.Of<IProjectSnapshotManagerProxy>(),
|
||||
_projectManager,
|
||||
Dispatcher,
|
||||
ErrorReporter,
|
||||
JoinableTaskFactory);
|
||||
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
|
||||
|
@ -166,7 +163,6 @@ public class ProjectSnapshotSynchronizationServiceTest : VisualStudioWorkspaceTe
|
|||
_sessionContext,
|
||||
StrictMock.Of<IProjectSnapshotManagerProxy>(),
|
||||
_projectManager,
|
||||
Dispatcher,
|
||||
ErrorReporter,
|
||||
JoinableTaskFactory);
|
||||
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
|
||||
|
@ -211,7 +207,6 @@ public class ProjectSnapshotSynchronizationServiceTest : VisualStudioWorkspaceTe
|
|||
_sessionContext,
|
||||
StrictMock.Of<IProjectSnapshotManagerProxy>(),
|
||||
_projectManager,
|
||||
Dispatcher,
|
||||
ErrorReporter,
|
||||
JoinableTaskFactory);
|
||||
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
|
||||
|
|
|
@ -54,7 +54,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
using var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
// Act
|
||||
|
@ -85,7 +84,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
using var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
var proxyAccessor = proxy.GetTestAccessor();
|
||||
|
@ -134,7 +132,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
var proxyAccessor = proxy.GetTestAccessor();
|
||||
|
@ -174,7 +171,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
using var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
// Act
|
||||
|
@ -210,7 +206,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
using var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
// Act
|
||||
|
@ -241,7 +236,6 @@ public class ProjectSnapshotManagerProxyTest(ITestOutputHelper testOutput) : Vis
|
|||
using var proxy = new ProjectSnapshotManagerProxy(
|
||||
new TestCollaborationSession(true),
|
||||
projectManager,
|
||||
Dispatcher,
|
||||
JoinableTaskFactory);
|
||||
|
||||
// Act
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor.Test;
|
||||
|
||||
|
@ -21,10 +21,12 @@ internal class TestProjectWorkspaceStateGenerator : IProjectWorkspaceStateGenera
|
|||
|
||||
public IReadOnlyList<TestUpdate> Updates => _updates;
|
||||
|
||||
public void Update(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
|
||||
public Task UpdateAsync(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
|
||||
{
|
||||
var update = new TestUpdate(workspaceProject, projectSnapshot, cancellationToken);
|
||||
_updates.Add(update);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
|
|
@ -124,7 +124,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
using var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
using var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
var workspaceChangedTask = detectorAccessor.ListenForWorkspaceChangesAsync(
|
||||
|
@ -166,7 +166,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
using var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
using var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -207,7 +207,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -250,7 +250,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -284,7 +284,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -324,7 +324,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -360,7 +360,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
Workspace.TryApplyChanges(_solutionWithTwoProjects);
|
||||
|
@ -392,7 +392,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
Workspace.TryApplyChanges(_solutionWithTwoProjects);
|
||||
|
@ -424,7 +424,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
Workspace.TryApplyChanges(_solutionWithTwoProjects);
|
||||
|
@ -456,7 +456,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
Workspace.TryApplyChanges(_solutionWithTwoProjects);
|
||||
|
@ -505,7 +505,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
@ -533,7 +533,7 @@ public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTest
|
|||
// Arrange
|
||||
var generator = new TestProjectWorkspaceStateGenerator();
|
||||
var projectManager = CreateProjectSnapshotManager();
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, Dispatcher);
|
||||
var detector = new WorkspaceProjectStateChangeDetector(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider);
|
||||
var detectorAccessor = detector.GetTestAccessor();
|
||||
|
||||
await projectManager.UpdateAsync(updater =>
|
||||
|
|
|
@ -61,10 +61,7 @@ public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
|
|||
// Act
|
||||
stateGenerator.Dispose();
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(stateGenerator.Updates);
|
||||
|
@ -79,10 +76,7 @@ public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
|
|||
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
|
||||
// Assert
|
||||
var update = Assert.Single(stateGenerator.Updates);
|
||||
|
@ -97,18 +91,12 @@ public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
|
|||
_projectManager, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
|
||||
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
|
||||
var initialUpdate = stateGenerator.Updates.Single().Value;
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
|
||||
// Assert
|
||||
Assert.True(initialUpdate.Cts.IsCancellationRequested);
|
||||
|
@ -129,10 +117,7 @@ public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
|
|||
});
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(workspaceProject: null, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(workspaceProject: null, _projectSnapshot, DisposalToken);
|
||||
|
||||
// Jump off the UI thread so the background work can complete.
|
||||
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
|
||||
|
@ -157,10 +142,7 @@ public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
|
|||
});
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
});
|
||||
await stateGenerator.UpdateAsync(_workspaceProject, _projectSnapshot, DisposalToken);
|
||||
|
||||
// Jump off the UI thread so the background work can complete.
|
||||
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
|
||||
|
|
|
@ -96,7 +96,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
StrictMock.Of<IProjectWorkspaceStateGenerator>(),
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext))
|
||||
{
|
||||
var testAccessor = trigger.GetTestAccessor();
|
||||
|
@ -136,7 +135,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
StrictMock.Of<IProjectWorkspaceStateGenerator>(),
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext);
|
||||
|
||||
var testAccessor = trigger.GetTestAccessor();
|
||||
|
@ -178,7 +176,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
workspaceStateGenerator,
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext);
|
||||
|
||||
var testAccessor = trigger.GetTestAccessor();
|
||||
|
@ -226,7 +223,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
workspaceStateGenerator,
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext);
|
||||
|
||||
var vsHierarchyMock = new StrictMock<IVsHierarchy>();
|
||||
|
@ -278,7 +274,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
workspaceStateGenerator,
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext);
|
||||
|
||||
var testAccessor = trigger.GetTestAccessor();
|
||||
|
@ -315,7 +310,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
|
|||
projectManager,
|
||||
workspaceStateGenerator,
|
||||
_workspaceProvider,
|
||||
Dispatcher,
|
||||
JoinableTaskContext);
|
||||
|
||||
var testAccessor = trigger.GetTestAccessor();
|
||||
|
|
|
@ -44,7 +44,6 @@ public class RazorDirectiveAttributeCompletionSourceTest(ITestOutputHelper testO
|
|||
var descriptionFactory = StrictMock.Of<IVisualStudioDescriptionFactory>(f =>
|
||||
f.CreateClassifiedDescription(description) == expectedResult);
|
||||
var source = new RazorDirectiveAttributeCompletionSource(
|
||||
Dispatcher,
|
||||
StrictMock.Of<IVisualStudioRazorParser>(),
|
||||
StrictMock.Of<IRazorCompletionFactsService>(),
|
||||
StrictMock.Of<ICompletionBroker>(),
|
||||
|
@ -234,7 +233,6 @@ public class RazorDirectiveAttributeCompletionSourceTest(ITestOutputHelper testO
|
|||
private RazorDirectiveAttributeCompletionSource CreateCompletionSource()
|
||||
{
|
||||
var source = new RazorDirectiveAttributeCompletionSource(
|
||||
Dispatcher,
|
||||
StrictMock.Of<IVisualStudioRazorParser>(),
|
||||
StrictMock.Of<IRazorCompletionFactsService>(),
|
||||
StrictMock.Of<ICompletionBroker>(),
|
||||
|
|
|
@ -76,17 +76,11 @@ public class ImportDocumentManagerIntegrationTest : VisualStudioTestBase
|
|||
.Returns(StrictMock.Of<IFileChangeTracker>());
|
||||
|
||||
var called = false;
|
||||
var manager = new ImportDocumentManager(Dispatcher, fileChangeTrackerFactoryMock.Object);
|
||||
var manager = new ImportDocumentManager(fileChangeTrackerFactoryMock.Object);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(tracker);
|
||||
});
|
||||
manager.OnSubscribed(tracker);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(anotherTracker);
|
||||
});
|
||||
manager.OnSubscribed(anotherTracker);
|
||||
|
||||
manager.Changed += (sender, args) =>
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.Test.Common;
|
||||
using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio;
|
||||
|
@ -37,7 +36,7 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task OnSubscribed_StartsFileChangeTrackers()
|
||||
public void OnSubscribed_StartsFileChangeTrackers()
|
||||
{
|
||||
// Arrange
|
||||
var tracker = StrictMock.Of<IVisualStudioDocumentTracker>(t =>
|
||||
|
@ -71,13 +70,10 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
.Returns(fileChangeTracker3Mock.Object)
|
||||
.Verifiable();
|
||||
|
||||
var manager = new ImportDocumentManager(Dispatcher, fileChangeTrackerFactoryMock.Object);
|
||||
var manager = new ImportDocumentManager(fileChangeTrackerFactoryMock.Object);
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(tracker);
|
||||
});
|
||||
manager.OnSubscribed(tracker);
|
||||
|
||||
// Assert
|
||||
fileChangeTrackerFactoryMock.Verify();
|
||||
|
@ -87,7 +83,7 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task OnSubscribed_AlreadySubscribed_DoesNothing()
|
||||
public void OnSubscribed_AlreadySubscribed_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var tracker = StrictMock.Of<IVisualStudioDocumentTracker>(t =>
|
||||
|
@ -113,25 +109,19 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
.Returns(fileChangeTrackerMock.Object)
|
||||
.Callback(() => callCount++);
|
||||
|
||||
var manager = new ImportDocumentManager(Dispatcher, fileChangeTrackerFactoryMock.Object);
|
||||
var manager = new ImportDocumentManager(fileChangeTrackerFactoryMock.Object);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||
});
|
||||
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(anotherTracker);
|
||||
});
|
||||
manager.OnSubscribed(anotherTracker);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, callCount);
|
||||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task OnUnsubscribed_StopsFileChangeTracker()
|
||||
public void OnUnsubscribed_StopsFileChangeTracker()
|
||||
{
|
||||
// Arrange
|
||||
var tracker = StrictMock.Of<IVisualStudioDocumentTracker>(t =>
|
||||
|
@ -152,18 +142,12 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
.Returns(fileChangeTrackerMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
var manager = new ImportDocumentManager(Dispatcher, fileChangeTrackerFactoryMock.Object);
|
||||
var manager = new ImportDocumentManager(fileChangeTrackerFactoryMock.Object);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||
});
|
||||
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnUnsubscribed(tracker);
|
||||
});
|
||||
manager.OnUnsubscribed(tracker);
|
||||
|
||||
// Assert
|
||||
fileChangeTrackerFactoryMock.Verify();
|
||||
|
@ -171,7 +155,7 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task OnUnsubscribed_AnotherDocumentTrackingImport_DoesNotStopFileChangeTracker()
|
||||
public void OnUnsubscribed_AnotherDocumentTrackingImport_DoesNotStopFileChangeTracker()
|
||||
{
|
||||
// Arrange
|
||||
var tracker = StrictMock.Of<IVisualStudioDocumentTracker>(t =>
|
||||
|
@ -198,20 +182,14 @@ public class ImportDocumentManagerTest : VisualStudioTestBase
|
|||
.Setup(f => f.Create(It.IsAny<string>()))
|
||||
.Returns(fileChangeTrackerMock.Object);
|
||||
|
||||
var manager = new ImportDocumentManager(Dispatcher, fileChangeTrackerFactoryMock.Object);
|
||||
var manager = new ImportDocumentManager(fileChangeTrackerFactoryMock.Object);
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnSubscribed(tracker); // Starts tracking import for the first document.
|
||||
manager.OnSubscribed(tracker); // Starts tracking import for the first document.
|
||||
|
||||
manager.OnSubscribed(anotherTracker); // Starts tracking import for the second document.
|
||||
});
|
||||
manager.OnSubscribed(anotherTracker); // Starts tracking import for the second document.
|
||||
|
||||
// Act & Assert (Does not throw)
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
manager.OnUnsubscribed(tracker);
|
||||
manager.OnUnsubscribed(tracker);
|
||||
});
|
||||
manager.OnUnsubscribed(tracker);
|
||||
manager.OnUnsubscribed(tracker);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
{
|
||||
// Arrange
|
||||
var editorFactoryService = StrictMock.Of<IRazorEditorFactoryService>();
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, JoinableTaskContext);
|
||||
var textView = StrictMock.Of<ITextView>();
|
||||
var nonCoreTextBuffer = VsMocks.CreateTextBuffer(core: false);
|
||||
|
||||
|
@ -64,7 +64,6 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
var coreTextBuffer = VsMocks.CreateTextBuffer(core: true);
|
||||
|
||||
IVisualStudioDocumentTracker? documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
FilePath,
|
||||
ProjectPath,
|
||||
|
@ -75,7 +74,7 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
_importDocumentManager);
|
||||
var editorFactoryService = StrictMock.Of<IRazorEditorFactoryService>(f =>
|
||||
f.TryGetDocumentTracker(coreTextBuffer, out documentTracker) == true);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, JoinableTaskContext);
|
||||
|
||||
// Act
|
||||
await documentManager.OnTextViewOpenedAsync(textView, [coreTextBuffer]);
|
||||
|
@ -93,7 +92,6 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
var nonCoreTextBuffer = VsMocks.CreateTextBuffer(core: false);
|
||||
|
||||
IVisualStudioDocumentTracker? documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
FilePath,
|
||||
ProjectPath,
|
||||
|
@ -104,7 +102,7 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
_importDocumentManager);
|
||||
var editorFactoryService = StrictMock.Of<IRazorEditorFactoryService>(f =>
|
||||
f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, JoinableTaskContext);
|
||||
|
||||
// Assert 1
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
|
@ -120,7 +118,7 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
public async Task OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var documentManager = new RazorDocumentManager(StrictMock.Of<IRazorEditorFactoryService>(), Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(StrictMock.Of<IRazorEditorFactoryService>(), JoinableTaskContext);
|
||||
var textView = StrictMock.Of<ITextView>();
|
||||
var coreTextBuffer = VsMocks.CreateTextBuffer(core: true);
|
||||
|
||||
|
@ -142,7 +140,6 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
|
||||
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
||||
var documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
FilePath,
|
||||
ProjectPath,
|
||||
|
@ -156,14 +153,14 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
coreTextBuffer.Properties.AddProperty(typeof(IVisualStudioDocumentTracker), documentTracker);
|
||||
|
||||
documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
|
||||
JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
|
||||
ProjectEngineFactories.DefaultProvider, nonCoreTextBuffer, _importDocumentManager);
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
nonCoreTextBuffer.Properties.AddProperty(typeof(IVisualStudioDocumentTracker), documentTracker);
|
||||
|
||||
var editorFactoryService = StrictMock.Of<IRazorEditorFactoryService>();
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, JoinableTaskContext);
|
||||
|
||||
// Act
|
||||
await documentManager.OnTextViewClosedAsync(textView2, [coreTextBuffer, nonCoreTextBuffer]);
|
||||
|
@ -186,7 +183,6 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
var nonCoreTextBuffer = VsMocks.CreateTextBuffer(core: false);
|
||||
|
||||
var documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher,
|
||||
JoinableTaskContext,
|
||||
FilePath,
|
||||
ProjectPath,
|
||||
|
@ -198,10 +194,10 @@ public class RazorDocumentManagerTest : VisualStudioTestBase
|
|||
|
||||
coreTextBuffer.Properties.AddProperty(typeof(IVisualStudioDocumentTracker), documentTracker);
|
||||
var editorFactoryService = StrictMock.Of<IRazorEditorFactoryService>();
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, Dispatcher, JoinableTaskContext);
|
||||
var documentManager = new RazorDocumentManager(editorFactoryService, JoinableTaskContext);
|
||||
|
||||
// Populate the text views
|
||||
await RunOnDispatcherAsync(documentTracker.Subscribe);
|
||||
documentTracker.Subscribe();
|
||||
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
|
|
|
@ -59,7 +59,6 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
_otherHostProject = new HostProject(TestProjectData.AnotherProject.FilePath, TestProjectData.AnotherProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.AnotherProject.RootNamespace);
|
||||
|
||||
_documentTracker = new VisualStudioDocumentTracker(
|
||||
Dispatcher,
|
||||
JoinableTaskFactory.Context,
|
||||
_filePath,
|
||||
projectPath,
|
||||
|
@ -82,53 +81,53 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Subscribe_NoopsIfAlreadySubscribed()
|
||||
public void Subscribe_NoopsIfAlreadySubscribed()
|
||||
{
|
||||
// Arrange
|
||||
var callCount = 0;
|
||||
_documentTracker.ContextChanged += (sender, args) => callCount++;
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, callCount);
|
||||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Unsubscribe_NoopsIfAlreadyUnsubscribed()
|
||||
public void Unsubscribe_NoopsIfAlreadyUnsubscribed()
|
||||
{
|
||||
// Arrange
|
||||
var callCount = 0;
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
_documentTracker.ContextChanged += (sender, args) => callCount++;
|
||||
await RunOnDispatcherAsync(_documentTracker.Unsubscribe);
|
||||
_documentTracker.Unsubscribe();
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Unsubscribe);
|
||||
_documentTracker.Unsubscribe();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, callCount);
|
||||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Unsubscribe_NoopsIfSubscribeHasBeenCalledMultipleTimes()
|
||||
public void Unsubscribe_NoopsIfSubscribeHasBeenCalledMultipleTimes()
|
||||
{
|
||||
// Arrange
|
||||
var callCount = 0;
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
_documentTracker.Subscribe();
|
||||
_documentTracker.ContextChanged += (sender, args) => callCount++;
|
||||
|
||||
// Act - 1
|
||||
await RunOnDispatcherAsync(_documentTracker.Unsubscribe);
|
||||
_documentTracker.Unsubscribe();
|
||||
|
||||
// Assert - 1
|
||||
Assert.Equal(0, callCount);
|
||||
|
||||
// Act - 2
|
||||
await RunOnDispatcherAsync(_documentTracker.Unsubscribe);
|
||||
_documentTracker.Unsubscribe();
|
||||
|
||||
// Assert - 2
|
||||
Assert.Equal(1, callCount);
|
||||
|
@ -273,7 +272,7 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Import_Changed_ImportAssociatedWithDocument_TriggersContextChanged()
|
||||
public void Import_Changed_ImportAssociatedWithDocument_TriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
var called = false;
|
||||
|
@ -286,17 +285,14 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
var importChangedArgs = new ImportChangedEventArgs("path/to/import", FileChangeKind.Changed, [_filePath]);
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
_documentTracker.Import_Changed(null!, importChangedArgs);
|
||||
});
|
||||
_documentTracker.Import_Changed(null!, importChangedArgs);
|
||||
|
||||
// Assert
|
||||
Assert.True(called);
|
||||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Import_Changed_UnrelatedImport_DoesNothing()
|
||||
public void Import_Changed_UnrelatedImport_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
_documentTracker.ContextChanged += (sender, args) => throw new InvalidOperationException();
|
||||
|
@ -304,21 +300,18 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
var importChangedArgs = new ImportChangedEventArgs("path/to/import", FileChangeKind.Changed, ["path/to/differentfile"]);
|
||||
|
||||
// Act & Assert (Does not throw)
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
_documentTracker.Import_Changed(null!, importChangedArgs);
|
||||
});
|
||||
_documentTracker.Import_Changed(null!, importChangedArgs);
|
||||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Subscribe_SetsSupportedProjectAndTriggersContextChanged()
|
||||
public void Subscribe_SetsSupportedProjectAndTriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
var called = false;
|
||||
_documentTracker.ContextChanged += (sender, args) => called = true;
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
// Assert
|
||||
Assert.True(called);
|
||||
|
@ -326,12 +319,12 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
|
||||
public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
// Subscribe once to set supported project
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
var called = false;
|
||||
_documentTracker.ContextChanged += (sender, args) =>
|
||||
|
@ -341,7 +334,7 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
};
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Unsubscribe);
|
||||
_documentTracker.Unsubscribe();
|
||||
|
||||
// Assert
|
||||
Assert.False(_documentTracker.IsSupportedProject);
|
||||
|
@ -447,12 +440,12 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
}
|
||||
|
||||
[UIFact]
|
||||
public async Task Subscribed_InitializesEphemeralProjectSnapshot()
|
||||
public void Subscribed_InitializesEphemeralProjectSnapshot()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<EphemeralProjectSnapshot>(_documentTracker.ProjectSnapshot);
|
||||
|
@ -468,7 +461,7 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
});
|
||||
|
||||
// Act
|
||||
await RunOnDispatcherAsync(_documentTracker.Subscribe);
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<ProjectSnapshot>(_documentTracker.ProjectSnapshot);
|
||||
|
@ -483,10 +476,7 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
updater.ProjectAdded(_hostProject);
|
||||
});
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
_documentTracker.Subscribe();
|
||||
});
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
var args = new List<ContextChangeEventArgs>();
|
||||
_documentTracker.ContextChanged += (sender, e) => args.Add(e);
|
||||
|
@ -515,10 +505,7 @@ public class VisualStudioDocumentTrackerTest : VisualStudioWorkspaceTestBase
|
|||
updater.ProjectAdded(_hostProject);
|
||||
});
|
||||
|
||||
await RunOnDispatcherAsync(() =>
|
||||
{
|
||||
_documentTracker.Subscribe();
|
||||
});
|
||||
_documentTracker.Subscribe();
|
||||
|
||||
var args = new List<ContextChangeEventArgs>();
|
||||
_documentTracker.ContextChanged += (sender, e) => args.Add(e);
|
||||
|
|
Загрузка…
Ссылка в новой задаче