parent
99cb120571
commit
8abbaa46cc
|
|
@ -30,6 +30,6 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
public override string PhysicalPath => File.FullName;
|
public override string PhysicalPath => File.FullName;
|
||||||
|
|
||||||
public override Stream Read() => File.OpenRead();
|
public override Stream Read() => new FileStream(PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +184,6 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
var result = new List<RazorSourceDocument>();
|
var result = new List<RazorSourceDocument>();
|
||||||
|
|
||||||
|
|
||||||
var importProjectItems = GetImportItems(projectItem);
|
var importProjectItems = GetImportItems(projectItem);
|
||||||
foreach (var importItem in importProjectItems)
|
foreach (var importItem in importProjectItems)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.VisualStudio.Text;
|
using Microsoft.VisualStudio.Text;
|
||||||
using Microsoft.VisualStudio.Text.Editor;
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
|
||||||
|
|
@ -14,13 +15,15 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
[Export(typeof(RazorDocumentManager))]
|
[Export(typeof(RazorDocumentManager))]
|
||||||
internal class DefaultRazorDocumentManager : RazorDocumentManager
|
internal class DefaultRazorDocumentManager : RazorDocumentManager
|
||||||
{
|
{
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
private readonly RazorEditorFactoryService _editorFactoryService;
|
private readonly RazorEditorFactoryService _editorFactoryService;
|
||||||
private readonly TextBufferProjectService _projectService;
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
|
||||||
[ImportingConstructor]
|
[ImportingConstructor]
|
||||||
public DefaultRazorDocumentManager(
|
public DefaultRazorDocumentManager(
|
||||||
RazorEditorFactoryService editorFactoryService,
|
RazorEditorFactoryService editorFactoryService,
|
||||||
TextBufferProjectService projectService)
|
TextBufferProjectService projectService,
|
||||||
|
VisualStudioWorkspaceAccessor workspaceAccessor)
|
||||||
{
|
{
|
||||||
if (editorFactoryService == null)
|
if (editorFactoryService == null)
|
||||||
{
|
{
|
||||||
|
|
@ -32,8 +35,40 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
throw new ArgumentNullException(nameof(projectService));
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workspaceAccessor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
_editorFactoryService = editorFactoryService;
|
_editorFactoryService = editorFactoryService;
|
||||||
_projectService = projectService;
|
_projectService = projectService;
|
||||||
|
_foregroundDispatcher = workspaceAccessor.Workspace.Services.GetRequiredService<ForegroundDispatcher>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only for testing. We want to avoid using the actual Roslyn GetService methods in unit tests.
|
||||||
|
internal DefaultRazorDocumentManager(
|
||||||
|
RazorEditorFactoryService editorFactoryService,
|
||||||
|
TextBufferProjectService projectService,
|
||||||
|
ForegroundDispatcher foregroundDispatcher)
|
||||||
|
{
|
||||||
|
if (editorFactoryService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(editorFactoryService));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foregroundDispatcher == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
_editorFactoryService = editorFactoryService;
|
||||||
|
_projectService = projectService;
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnTextViewOpened(ITextView textView, IEnumerable<ITextBuffer> subjectBuffers)
|
public override void OnTextViewOpened(ITextView textView, IEnumerable<ITextBuffer> subjectBuffers)
|
||||||
|
|
@ -48,6 +83,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
throw new ArgumentNullException(nameof(subjectBuffers));
|
throw new ArgumentNullException(nameof(subjectBuffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
foreach (var textBuffer in subjectBuffers)
|
foreach (var textBuffer in subjectBuffers)
|
||||||
{
|
{
|
||||||
if (!textBuffer.IsRazorBuffer())
|
if (!textBuffer.IsRazorBuffer())
|
||||||
|
|
@ -88,6 +125,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
throw new ArgumentNullException(nameof(subjectBuffers));
|
throw new ArgumentNullException(nameof(subjectBuffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
// This means a Razor buffer has be detached from this ITextView or the ITextView is closing. Since we keep a
|
// This means a Razor buffer has be detached from this ITextView or the ITextView is closing. Since we keep a
|
||||||
// list of all of the open text views for each text buffer, we need to update the tracker.
|
// list of all of the open text views for each text buffer, we need to update the tracker.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
private readonly ProjectSnapshotManager _projectManager;
|
private readonly ProjectSnapshotManager _projectManager;
|
||||||
private readonly EditorSettingsManagerInternal _editorSettingsManager;
|
private readonly EditorSettingsManagerInternal _editorSettingsManager;
|
||||||
private readonly ITextBuffer _textBuffer;
|
private readonly ITextBuffer _textBuffer;
|
||||||
|
private readonly ImportDocumentManager _importDocumentManager;
|
||||||
private readonly List<ITextView> _textViews;
|
private readonly List<ITextView> _textViews;
|
||||||
private readonly Workspace _workspace;
|
private readonly Workspace _workspace;
|
||||||
private bool _isSupportedProject;
|
private bool _isSupportedProject;
|
||||||
|
|
@ -32,7 +33,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
ProjectSnapshotManager projectManager,
|
ProjectSnapshotManager projectManager,
|
||||||
EditorSettingsManagerInternal editorSettingsManager,
|
EditorSettingsManagerInternal editorSettingsManager,
|
||||||
Workspace workspace,
|
Workspace workspace,
|
||||||
ITextBuffer textBuffer)
|
ITextBuffer textBuffer,
|
||||||
|
ImportDocumentManager importDocumentManager)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(filePath))
|
if (string.IsNullOrEmpty(filePath))
|
||||||
{
|
{
|
||||||
|
|
@ -64,11 +66,17 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
throw new ArgumentNullException(nameof(textBuffer));
|
throw new ArgumentNullException(nameof(textBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (importDocumentManager == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(importDocumentManager));
|
||||||
|
}
|
||||||
|
|
||||||
_filePath = filePath;
|
_filePath = filePath;
|
||||||
_projectPath = projectPath;
|
_projectPath = projectPath;
|
||||||
_projectManager = projectManager;
|
_projectManager = projectManager;
|
||||||
_editorSettingsManager = editorSettingsManager;
|
_editorSettingsManager = editorSettingsManager;
|
||||||
_textBuffer = textBuffer;
|
_textBuffer = textBuffer;
|
||||||
|
_importDocumentManager = importDocumentManager;
|
||||||
_workspace = workspace; // For now we assume that the workspace is the always default VS workspace.
|
_workspace = workspace; // For now we assume that the workspace is the always default VS workspace.
|
||||||
|
|
||||||
_textViews = new List<ITextView>();
|
_textViews = new List<ITextView>();
|
||||||
|
|
@ -135,8 +143,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
public void Subscribe()
|
public void Subscribe()
|
||||||
{
|
{
|
||||||
|
_importDocumentManager.OnSubscribed(this);
|
||||||
|
|
||||||
_editorSettingsManager.Changed += EditorSettingsManager_Changed;
|
_editorSettingsManager.Changed += EditorSettingsManager_Changed;
|
||||||
_projectManager.Changed += ProjectManager_Changed;
|
_projectManager.Changed += ProjectManager_Changed;
|
||||||
|
_importDocumentManager.Changed += Import_Changed;
|
||||||
|
|
||||||
_isSupportedProject = true;
|
_isSupportedProject = true;
|
||||||
_project = _projectManager.GetProjectWithFilePath(_projectPath);
|
_project = _projectManager.GetProjectWithFilePath(_projectPath);
|
||||||
|
|
@ -146,8 +157,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
public void Unsubscribe()
|
public void Unsubscribe()
|
||||||
{
|
{
|
||||||
|
_importDocumentManager.OnUnsubscribed(this);
|
||||||
|
|
||||||
_projectManager.Changed -= ProjectManager_Changed;
|
_projectManager.Changed -= ProjectManager_Changed;
|
||||||
_editorSettingsManager.Changed -= EditorSettingsManager_Changed;
|
_editorSettingsManager.Changed -= EditorSettingsManager_Changed;
|
||||||
|
_importDocumentManager.Changed -= Import_Changed;
|
||||||
|
|
||||||
// Detached from project.
|
// Detached from project.
|
||||||
_isSupportedProject = false;
|
_isSupportedProject = false;
|
||||||
|
|
@ -189,5 +203,18 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
OnContextChanged(_project, ContextChangeKind.EditorSettingsChanged);
|
OnContextChanged(_project, ContextChangeKind.EditorSettingsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal void Import_Changed(object sender, ImportChangedEventArgs args)
|
||||||
|
{
|
||||||
|
foreach (var path in args.AssociatedDocuments)
|
||||||
|
{
|
||||||
|
if (string.Equals(_filePath, path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
OnContextChanged(_project, ContextChangeKind.ImportsChanged);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
internal enum ImportChangeKind
|
||||||
|
{
|
||||||
|
Added,
|
||||||
|
Removed,
|
||||||
|
Changed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
internal class ImportChangedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public ImportChangedEventArgs(string filePath, ImportChangeKind kind, IEnumerable<string> associatedDocuments)
|
||||||
|
{
|
||||||
|
FilePath = filePath;
|
||||||
|
Kind = kind;
|
||||||
|
AssociatedDocuments = associatedDocuments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FilePath { get; }
|
||||||
|
|
||||||
|
public ImportChangeKind Kind { get; }
|
||||||
|
|
||||||
|
public IEnumerable<string> AssociatedDocuments { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
internal abstract class ImportDocumentManager
|
||||||
|
{
|
||||||
|
public abstract event EventHandler<ImportChangedEventArgs> Changed;
|
||||||
|
|
||||||
|
public abstract void OnSubscribed(VisualStudioDocumentTracker tracker);
|
||||||
|
|
||||||
|
public abstract void OnUnsubscribed(VisualStudioDocumentTracker tracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using Microsoft.VisualStudio.Shell;
|
||||||
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
|
{
|
||||||
|
[System.Composition.Shared]
|
||||||
|
[Export(typeof(ImportDocumentManager))]
|
||||||
|
internal class DefaultImportDocumentManager : ImportDocumentManager
|
||||||
|
{
|
||||||
|
private const uint FileChangeFlags = (uint)(_VSFILECHANGEFLAGS.VSFILECHG_Time | _VSFILECHANGEFLAGS.VSFILECHG_Size | _VSFILECHANGEFLAGS.VSFILECHG_Del | _VSFILECHANGEFLAGS.VSFILECHG_Add);
|
||||||
|
|
||||||
|
private readonly IVsFileChangeEx _fileChangeService;
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
private readonly ErrorReporter _errorReporter;
|
||||||
|
private readonly RazorTemplateEngineFactoryService _templateEngineFactoryService;
|
||||||
|
private readonly Dictionary<string, ImportTracker> _importTrackerCache;
|
||||||
|
|
||||||
|
public override event EventHandler<ImportChangedEventArgs> Changed;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public DefaultImportDocumentManager(
|
||||||
|
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider,
|
||||||
|
VisualStudioWorkspaceAccessor workspaceAccessor)
|
||||||
|
{
|
||||||
|
if (serviceProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serviceProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspaceAccessor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
_fileChangeService = serviceProvider.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx;
|
||||||
|
|
||||||
|
var workspace = workspaceAccessor.Workspace;
|
||||||
|
_foregroundDispatcher = workspace.Services.GetRequiredService<ForegroundDispatcher>();
|
||||||
|
_errorReporter = workspace.Services.GetRequiredService<ErrorReporter>();
|
||||||
|
|
||||||
|
var razorLanguageServices = workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
||||||
|
_templateEngineFactoryService = razorLanguageServices.GetRequiredService<RazorTemplateEngineFactoryService>();
|
||||||
|
|
||||||
|
_importTrackerCache = new Dictionary<string, ImportTracker>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only used for testing.
|
||||||
|
internal DefaultImportDocumentManager(
|
||||||
|
IVsFileChangeEx fileChangeService,
|
||||||
|
RazorTemplateEngineFactoryService templateEngineFactoryService,
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
ErrorReporter errorReporter)
|
||||||
|
{
|
||||||
|
_fileChangeService = fileChangeService;
|
||||||
|
_templateEngineFactoryService = templateEngineFactoryService;
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
_errorReporter = errorReporter;
|
||||||
|
|
||||||
|
_importTrackerCache = new Dictionary<string, ImportTracker>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSubscribed(VisualStudioDocumentTracker tracker)
|
||||||
|
{
|
||||||
|
if (tracker == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(tracker));
|
||||||
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
var imports = GetImportItems(tracker);
|
||||||
|
foreach (var import in imports)
|
||||||
|
{
|
||||||
|
var importFilePath = import.PhysicalPath;
|
||||||
|
Debug.Assert(importFilePath != null);
|
||||||
|
|
||||||
|
if (!_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
|
||||||
|
{
|
||||||
|
// First time seeing this import. Start tracking it.
|
||||||
|
importTracker = new ImportTracker(importFilePath);
|
||||||
|
_importTrackerCache[importFilePath] = importTracker;
|
||||||
|
|
||||||
|
StartListeningForChanges(importTracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
importTracker.AssociatedDocuments.Add(tracker.FilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnUnsubscribed(VisualStudioDocumentTracker tracker)
|
||||||
|
{
|
||||||
|
if (tracker == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(tracker));
|
||||||
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
var imports = GetImportItems(tracker);
|
||||||
|
foreach (var import in imports)
|
||||||
|
{
|
||||||
|
var importFilePath = import.PhysicalPath;
|
||||||
|
Debug.Assert(importFilePath != null);
|
||||||
|
|
||||||
|
if (_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
|
||||||
|
{
|
||||||
|
importTracker.AssociatedDocuments.Remove(tracker.FilePath);
|
||||||
|
|
||||||
|
if (importTracker.AssociatedDocuments.Count == 0)
|
||||||
|
{
|
||||||
|
// There are no open documents that care about this import. We no longer need to track it.
|
||||||
|
StopListeningForChanges(importTracker);
|
||||||
|
_importTrackerCache.Remove(importFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<RazorProjectItem> GetImportItems(VisualStudioDocumentTracker tracker)
|
||||||
|
{
|
||||||
|
var projectDirectory = Path.GetDirectoryName(tracker.ProjectPath);
|
||||||
|
var templateEngine = _templateEngineFactoryService.Create(projectDirectory, _ => { });
|
||||||
|
var imports = templateEngine.GetImportItems(tracker.FilePath);
|
||||||
|
|
||||||
|
return imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FireImportChanged(string importPath, ImportChangeKind kind)
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
var handler = Changed;
|
||||||
|
if (handler != null && _importTrackerCache.TryGetValue(importPath, out var importTracker))
|
||||||
|
{
|
||||||
|
var args = new ImportChangedEventArgs(importPath, kind, importTracker.AssociatedDocuments);
|
||||||
|
handler(this, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal for testing.
|
||||||
|
internal void OnFilesChanged(uint fileCount, string[] filePaths, uint[] fileChangeFlags)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < fileCount; i++)
|
||||||
|
{
|
||||||
|
var kind = ImportChangeKind.Changed;
|
||||||
|
var flag = (_VSFILECHANGEFLAGS)fileChangeFlags[i];
|
||||||
|
|
||||||
|
if ((flag & _VSFILECHANGEFLAGS.VSFILECHG_Del) == _VSFILECHANGEFLAGS.VSFILECHG_Del)
|
||||||
|
{
|
||||||
|
kind = ImportChangeKind.Removed;
|
||||||
|
}
|
||||||
|
else if ((flag & _VSFILECHANGEFLAGS.VSFILECHG_Add) == _VSFILECHANGEFLAGS.VSFILECHG_Add)
|
||||||
|
{
|
||||||
|
kind = ImportChangeKind.Added;
|
||||||
|
}
|
||||||
|
|
||||||
|
FireImportChanged(filePaths[i], kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartListeningForChanges(ImportTracker importTracker)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (importTracker.FileChangeCookie == VSConstants.VSCOOKIE_NIL)
|
||||||
|
{
|
||||||
|
var hr = _fileChangeService.AdviseFileChange(
|
||||||
|
importTracker.FilePath,
|
||||||
|
FileChangeFlags,
|
||||||
|
new ImportDocumentEventSink(this, _foregroundDispatcher),
|
||||||
|
out var cookie);
|
||||||
|
|
||||||
|
Marshal.ThrowExceptionForHR(hr);
|
||||||
|
|
||||||
|
importTracker.FileChangeCookie = cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_errorReporter.ReportError(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopListeningForChanges(ImportTracker importTracker)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (importTracker.FileChangeCookie != VSConstants.VSCOOKIE_NIL)
|
||||||
|
{
|
||||||
|
var hr = _fileChangeService.UnadviseFileChange(importTracker.FileChangeCookie);
|
||||||
|
Marshal.ThrowExceptionForHR(hr);
|
||||||
|
importTracker.FileChangeCookie = VSConstants.VSCOOKIE_NIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_errorReporter.ReportError(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ImportTracker
|
||||||
|
{
|
||||||
|
public ImportTracker(string filePath)
|
||||||
|
{
|
||||||
|
FilePath = filePath;
|
||||||
|
AssociatedDocuments = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
FileChangeCookie = VSConstants.VSCOOKIE_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FilePath { get; }
|
||||||
|
|
||||||
|
public HashSet<string> AssociatedDocuments { get; }
|
||||||
|
|
||||||
|
public uint FileChangeCookie { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ImportDocumentEventSink : IVsFileChangeEvents
|
||||||
|
{
|
||||||
|
private readonly DefaultImportDocumentManager _importDocumentManager;
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
|
||||||
|
public ImportDocumentEventSink(DefaultImportDocumentManager importDocumentManager, ForegroundDispatcher foregroundDispatcher)
|
||||||
|
{
|
||||||
|
_importDocumentManager = importDocumentManager;
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FilesChanged(uint cChanges, string[] rgpszFile, uint[] rggrfChange)
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
_importDocumentManager.OnFilesChanged(cChanges, rgpszFile, rggrfChange);
|
||||||
|
|
||||||
|
return VSConstants.S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DirectoryChanged(string pszDirectory)
|
||||||
|
{
|
||||||
|
return VSConstants.S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Diagnostics;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.VisualStudio.Editor.Razor;
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
using Microsoft.VisualStudio.Shell;
|
using Microsoft.VisualStudio.Shell;
|
||||||
|
|
@ -71,7 +72,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
throw new ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
var hierarchy = (IVsHierarchy)project;
|
var hierarchy = project as IVsHierarchy;
|
||||||
|
Debug.Assert(hierarchy != null);
|
||||||
|
|
||||||
ErrorHandler.ThrowOnFailure(((IVsProject)hierarchy).GetMkDocument((uint)VSConstants.VSITEMID.Root, out var path), VSConstants.E_NOTIMPL);
|
ErrorHandler.ThrowOnFailure(((IVsProject)hierarchy).GetMkDocument((uint)VSConstants.VSITEMID.Root, out var path), VSConstants.E_NOTIMPL);
|
||||||
return path;
|
return path;
|
||||||
|
|
@ -84,7 +86,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
throw new ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
var hierarchy = (IVsHierarchy)project;
|
var hierarchy = project as IVsHierarchy;
|
||||||
|
Debug.Assert(hierarchy != null);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return hierarchy.IsCapabilityMatch(DotNetCoreCapability);
|
return hierarchy.IsCapabilityMatch(DotNetCoreCapability);
|
||||||
|
|
@ -108,7 +112,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
throw new ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
var hierarchy = (IVsHierarchy)project;
|
var hierarchy = project as IVsHierarchy;
|
||||||
|
Debug.Assert(hierarchy != null);
|
||||||
|
|
||||||
if (ErrorHandler.Failed(hierarchy.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out var name)))
|
if (ErrorHandler.Failed(hierarchy.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out var name)))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
private readonly TextBufferProjectService _projectService;
|
private readonly TextBufferProjectService _projectService;
|
||||||
private readonly ITextDocumentFactoryService _textDocumentFactory;
|
private readonly ITextDocumentFactoryService _textDocumentFactory;
|
||||||
private readonly Workspace _workspace;
|
private readonly Workspace _workspace;
|
||||||
|
private readonly ImportDocumentManager _importDocumentManager;
|
||||||
private readonly ForegroundDispatcher _foregroundDispatcher;
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
private readonly ProjectSnapshotManager _projectManager;
|
private readonly ProjectSnapshotManager _projectManager;
|
||||||
private readonly EditorSettingsManagerInternal _editorSettingsManager;
|
private readonly EditorSettingsManagerInternal _editorSettingsManager;
|
||||||
|
|
@ -28,7 +29,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
public DefaultVisualStudioDocumentTrackerFactory(
|
public DefaultVisualStudioDocumentTrackerFactory(
|
||||||
TextBufferProjectService projectService,
|
TextBufferProjectService projectService,
|
||||||
ITextDocumentFactoryService textDocumentFactory,
|
ITextDocumentFactoryService textDocumentFactory,
|
||||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
VisualStudioWorkspaceAccessor workspaceAccessor,
|
||||||
|
ImportDocumentManager importDocumentManager)
|
||||||
{
|
{
|
||||||
if (projectService == null)
|
if (projectService == null)
|
||||||
{
|
{
|
||||||
|
|
@ -40,17 +42,18 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
throw new ArgumentNullException(nameof(textDocumentFactory));
|
throw new ArgumentNullException(nameof(textDocumentFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspace == null)
|
if (workspaceAccessor == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(workspace));
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
}
|
}
|
||||||
|
|
||||||
_projectService = projectService;
|
_projectService = projectService;
|
||||||
_textDocumentFactory = textDocumentFactory;
|
_textDocumentFactory = textDocumentFactory;
|
||||||
_workspace = workspace;
|
_workspace = workspaceAccessor.Workspace;
|
||||||
|
_importDocumentManager = importDocumentManager;
|
||||||
|
|
||||||
_foregroundDispatcher = workspace.Services.GetRequiredService<ForegroundDispatcher>();
|
_foregroundDispatcher = _workspace.Services.GetRequiredService<ForegroundDispatcher>();
|
||||||
var razorLanguageServices = workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
var razorLanguageServices = _workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
||||||
_projectManager = razorLanguageServices.GetRequiredService<ProjectSnapshotManager>();
|
_projectManager = razorLanguageServices.GetRequiredService<ProjectSnapshotManager>();
|
||||||
_editorSettingsManager = razorLanguageServices.GetRequiredService<EditorSettingsManagerInternal>();
|
_editorSettingsManager = razorLanguageServices.GetRequiredService<EditorSettingsManagerInternal>();
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +81,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
|
||||||
var projectPath = _projectService.GetProjectPath(project);
|
var projectPath = _projectService.GetProjectPath(project);
|
||||||
|
|
||||||
var tracker = new DefaultVisualStudioDocumentTracker(filePath, projectPath, _projectManager, _editorSettingsManager, _workspace, textBuffer);
|
var tracker = new DefaultVisualStudioDocumentTracker(filePath, projectPath, _projectManager, _editorSettingsManager, _workspace, textBuffer, _importDocumentManager);
|
||||||
|
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.Editor.Razor
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
public class DefaultRazorDocumentManagerTest
|
public class DefaultRazorDocumentManagerTest : ForegroundDispatcherTestBase
|
||||||
{
|
{
|
||||||
private IContentType RazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
|
private IContentType RazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
|
||||||
|
|
||||||
|
|
@ -29,6 +29,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
|
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
|
||||||
|
|
||||||
|
private ImportDocumentManager ImportDocumentManager => Mock.Of<ImportDocumentManager>();
|
||||||
|
|
||||||
private Workspace Workspace => new AdhocWorkspace();
|
private Workspace Workspace => new AdhocWorkspace();
|
||||||
|
|
||||||
private TextBufferProjectService SupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(
|
private TextBufferProjectService SupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(
|
||||||
|
|
@ -38,12 +40,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
private TextBufferProjectService UnsupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<object>()) == false);
|
private TextBufferProjectService UnsupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<object>()) == false);
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewOpened_ForNonRazorCoreProject_DoesNothing()
|
public void OnTextViewOpened_ForNonRazorCoreProject_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, UnsupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, UnsupportedProjectService, Dispatcher);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
var buffers = new Collection<ITextBuffer>()
|
var buffers = new Collection<ITextBuffer>()
|
||||||
{
|
{
|
||||||
|
|
@ -54,12 +56,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
documentManager.OnTextViewOpened(textView, buffers);
|
documentManager.OnTextViewOpened(textView, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewOpened_ForNonRazorTextBuffer_DoesNothing()
|
public void OnTextViewOpened_ForNonRazorTextBuffer_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, SupportedProjectService, Dispatcher);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
var buffers = new Collection<ITextBuffer>()
|
var buffers = new Collection<ITextBuffer>()
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +72,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
documentManager.OnTextViewOpened(textView, buffers);
|
documentManager.OnTextViewOpened(textView, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewOpened_ForRazorTextBuffer_AddsTextViewToTracker()
|
public void OnTextViewOpened_ForRazorTextBuffer_AddsTextViewToTracker()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -79,9 +81,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
};
|
};
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0]) as VisualStudioDocumentTracker;
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
|
||||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService, Dispatcher);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
documentManager.OnTextViewOpened(textView, buffers);
|
documentManager.OnTextViewOpened(textView, buffers);
|
||||||
|
|
@ -90,7 +92,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView));
|
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewOpened_SubscribesAfterFirstTextViewOpened()
|
public void OnTextViewOpened_SubscribesAfterFirstTextViewOpened()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -100,9 +102,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||||
};
|
};
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0]) as VisualStudioDocumentTracker;
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
|
||||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(f => f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(f => f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService, Dispatcher);
|
||||||
|
|
||||||
// Assert 1
|
// Assert 1
|
||||||
Assert.False(documentTracker.IsSupportedProject);
|
Assert.False(documentTracker.IsSupportedProject);
|
||||||
|
|
@ -114,11 +116,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.True(documentTracker.IsSupportedProject);
|
Assert.True(documentTracker.IsSupportedProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewClosed_FoNonRazorCoreProject_DoesNothing()
|
public void OnTextViewClosed_FoNonRazorCoreProject_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), UnsupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), UnsupportedProjectService, Dispatcher);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
var buffers = new Collection<ITextBuffer>()
|
var buffers = new Collection<ITextBuffer>()
|
||||||
{
|
{
|
||||||
|
|
@ -132,11 +134,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing()
|
public void OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), SupportedProjectService, Dispatcher);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
var buffers = new Collection<ITextBuffer>()
|
var buffers = new Collection<ITextBuffer>()
|
||||||
{
|
{
|
||||||
|
|
@ -150,7 +152,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewClosed_ForAnyTextBufferWithTracker_RemovesTextView()
|
public void OnTextViewClosed_ForAnyTextBufferWithTracker_RemovesTextView()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -163,18 +165,18 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
};
|
};
|
||||||
|
|
||||||
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0]);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
|
||||||
documentTracker.AddTextView(textView1);
|
documentTracker.AddTextView(textView1);
|
||||||
documentTracker.AddTextView(textView2);
|
documentTracker.AddTextView(textView2);
|
||||||
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||||
|
|
||||||
documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[1]);
|
documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[1], ImportDocumentManager);
|
||||||
documentTracker.AddTextView(textView1);
|
documentTracker.AddTextView(textView1);
|
||||||
documentTracker.AddTextView(textView2);
|
documentTracker.AddTextView(textView2);
|
||||||
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||||
|
|
||||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService, Dispatcher);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
documentManager.OnTextViewClosed(textView2, buffers);
|
documentManager.OnTextViewClosed(textView2, buffers);
|
||||||
|
|
@ -187,7 +189,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1));
|
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ForegroundFact]
|
||||||
public void OnTextViewClosed_UnsubscribesAfterLastTextViewClosed()
|
public void OnTextViewClosed_UnsubscribesAfterLastTextViewClosed()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -198,10 +200,10 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||||
};
|
};
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0]);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
|
||||||
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
||||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService, Dispatcher);
|
||||||
|
|
||||||
// Populate the text views
|
// Populate the text views
|
||||||
documentTracker.Subscribe();
|
documentTracker.Subscribe();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
@ -30,11 +31,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
private Workspace Workspace => new AdhocWorkspace();
|
private Workspace Workspace => new AdhocWorkspace();
|
||||||
|
|
||||||
|
private ImportDocumentManager ImportDocumentManager => Mock.Of<ImportDocumentManager>();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void EditorSettingsManager_Changed_TriggersContextChanged()
|
public void EditorSettingsManager_Changed_TriggersContextChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var called = false;
|
var called = false;
|
||||||
documentTracker.ContextChanged += (sender, args) =>
|
documentTracker.ContextChanged += (sender, args) =>
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void ProjectManager_Changed_ProjectChanged_TriggersContextChanged()
|
public void ProjectManager_Changed_ProjectChanged_TriggersContextChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
|
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
|
||||||
var projectSnapshot = new DefaultProjectSnapshot(project);
|
var projectSnapshot = new DefaultProjectSnapshot(project);
|
||||||
|
|
@ -78,7 +81,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void ProjectManager_Changed_TagHelpersChanged_TriggersContextChanged()
|
public void ProjectManager_Changed_TagHelpersChanged_TriggersContextChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
|
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
|
||||||
var projectSnapshot = new DefaultProjectSnapshot(project);
|
var projectSnapshot = new DefaultProjectSnapshot(project);
|
||||||
|
|
@ -102,7 +105,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void ProjectManager_Changed_IgnoresUnknownProject()
|
public void ProjectManager_Changed_IgnoresUnknownProject()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Other/Path/TestProject.csproj"));
|
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Other/Path/TestProject.csproj"));
|
||||||
var projectSnapshot = new DefaultProjectSnapshot(project);
|
var projectSnapshot = new DefaultProjectSnapshot(project);
|
||||||
|
|
@ -121,11 +124,50 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
Assert.False(called);
|
Assert.False(called);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Import_Changed_ImportAssociatedWithDocument_TriggersContextChanged()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
|
var called = false;
|
||||||
|
documentTracker.ContextChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(ContextChangeKind.ImportsChanged, args.Kind);
|
||||||
|
called = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var importChangedArgs = new ImportChangedEventArgs("path/to/import", ImportChangeKind.Changed, new[] { FilePath });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
documentTracker.Import_Changed(null, importChangedArgs);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(called);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Import_Changed_UnrelatedImport_DoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
|
documentTracker.ContextChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
};
|
||||||
|
|
||||||
|
var importChangedArgs = new ImportChangedEventArgs("path/to/import", ImportChangeKind.Changed, new[] { "path/to/differentfile" });
|
||||||
|
|
||||||
|
// Act & Assert (Does not throw)
|
||||||
|
documentTracker.Import_Changed(null, importChangedArgs);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Subscribe_SetsSupportedProjectAndTriggersContextChanged()
|
public void Subscribe_SetsSupportedProjectAndTriggersContextChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var called = false;
|
var called = false;
|
||||||
documentTracker.ContextChanged += (sender, args) =>
|
documentTracker.ContextChanged += (sender, args) =>
|
||||||
{
|
{
|
||||||
|
|
@ -145,7 +187,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
|
public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
|
|
||||||
// Subscribe once to set supported project
|
// Subscribe once to set supported project
|
||||||
documentTracker.Subscribe();
|
documentTracker.Subscribe();
|
||||||
|
|
@ -169,7 +211,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void AddTextView_AddsToTextViewCollection()
|
public void AddTextView_AddsToTextViewCollection()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -183,7 +225,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void AddTextView_DoesNotAddDuplicateTextViews()
|
public void AddTextView_DoesNotAddDuplicateTextViews()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -198,7 +240,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void AddTextView_AddsMultipleTextViewsToCollection()
|
public void AddTextView_AddsMultipleTextViewsToCollection()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView1 = Mock.Of<ITextView>();
|
var textView1 = Mock.Of<ITextView>();
|
||||||
var textView2 = Mock.Of<ITextView>();
|
var textView2 = Mock.Of<ITextView>();
|
||||||
|
|
||||||
|
|
@ -217,7 +259,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void RemoveTextView_RemovesTextViewFromCollection_SingleItem()
|
public void RemoveTextView_RemovesTextViewFromCollection_SingleItem()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView = Mock.Of<ITextView>();
|
var textView = Mock.Of<ITextView>();
|
||||||
documentTracker.AddTextView(textView);
|
documentTracker.AddTextView(textView);
|
||||||
|
|
||||||
|
|
@ -232,7 +274,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void RemoveTextView_RemovesTextViewFromCollection_MultipleItems()
|
public void RemoveTextView_RemovesTextViewFromCollection_MultipleItems()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView1 = Mock.Of<ITextView>();
|
var textView1 = Mock.Of<ITextView>();
|
||||||
var textView2 = Mock.Of<ITextView>();
|
var textView2 = Mock.Of<ITextView>();
|
||||||
var textView3 = Mock.Of<ITextView>();
|
var textView3 = Mock.Of<ITextView>();
|
||||||
|
|
@ -254,7 +296,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
public void RemoveTextView_NoopsWhenRemovingTextViewNotInCollection()
|
public void RemoveTextView_NoopsWhenRemovingTextViewNotInCollection()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
|
||||||
var textView1 = Mock.Of<ITextView>();
|
var textView1 = Mock.Of<ITextView>();
|
||||||
documentTracker.AddTextView(textView1);
|
documentTracker.AddTextView(textView1);
|
||||||
var textView2 = Mock.Of<ITextView>();
|
var textView2 = Mock.Of<ITextView>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
|
{
|
||||||
|
public class DefaultImportDocumentManagerTest : ForegroundDispatcherTestBase
|
||||||
|
{
|
||||||
|
[ForegroundFact]
|
||||||
|
public void OnSubscribed_StartTrackingImport()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = "C:\\path\\to\\project\\Views\\Home\\file.cshtml";
|
||||||
|
var projectPath = "C:\\path\\to\\project\\project.csproj";
|
||||||
|
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
|
||||||
|
var templateEngineFactoryService = GetTemplateEngineFactoryService();
|
||||||
|
|
||||||
|
uint cookie;
|
||||||
|
var fileChangeService = new Mock<IVsFileChangeEx>(MockBehavior.Strict);
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange("C:\\path\\to\\project\\Views\\Home\\_ViewImports.cshtml", It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Verifiable();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange("C:\\path\\to\\project\\Views\\_ViewImports.cshtml", It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Verifiable();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange("C:\\path\\to\\project\\_ViewImports.cshtml", It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var manager = new DefaultImportDocumentManager(fileChangeService.Object, templateEngineFactoryService, Dispatcher, new DefaultErrorReporter());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
manager.OnSubscribed(tracker);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
fileChangeService.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ForegroundFact]
|
||||||
|
public void OnSubscribed_AlreadyTrackingImport_DoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = "C:\\path\\to\\project\\file.cshtml";
|
||||||
|
var projectPath = "C:\\path\\to\\project\\project.csproj";
|
||||||
|
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
|
||||||
|
var templateEngineFactoryService = GetTemplateEngineFactoryService();
|
||||||
|
|
||||||
|
uint cookie;
|
||||||
|
var callCount = 0;
|
||||||
|
var fileChangeService = new Mock<IVsFileChangeEx>();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange(It.IsAny<string>(), It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Callback(() => callCount++);
|
||||||
|
|
||||||
|
var manager = new DefaultImportDocumentManager(fileChangeService.Object, templateEngineFactoryService, Dispatcher, new DefaultErrorReporter());
|
||||||
|
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||||
|
|
||||||
|
var anotherFilePath = "C:\\path\\to\\project\\anotherFile.cshtml";
|
||||||
|
var anotherTracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == anotherFilePath && t.ProjectPath == projectPath);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
manager.OnSubscribed(anotherTracker);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, callCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ForegroundFact]
|
||||||
|
public void OnUnsubscribed_StopsTrackingImport()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = "C:\\path\\to\\project\\file.cshtml";
|
||||||
|
var projectPath = "C:\\path\\to\\project\\project.csproj";
|
||||||
|
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
|
||||||
|
var templateEngineFactoryService = GetTemplateEngineFactoryService();
|
||||||
|
|
||||||
|
uint cookie = 100;
|
||||||
|
var fileChangeService = new Mock<IVsFileChangeEx>(MockBehavior.Strict);
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange("C:\\path\\to\\project\\_ViewImports.cshtml", It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Verifiable();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.UnadviseFileChange(cookie))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var manager = new DefaultImportDocumentManager(fileChangeService.Object, templateEngineFactoryService, Dispatcher, new DefaultErrorReporter());
|
||||||
|
manager.OnSubscribed(tracker); // Start tracking the import.
|
||||||
|
|
||||||
|
// Act
|
||||||
|
manager.OnUnsubscribed(tracker);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
fileChangeService.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ForegroundFact]
|
||||||
|
public void OnUnsubscribed_AnotherDocumentTrackingImport_DoesNotStopTrackingImport()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = "C:\\path\\to\\project\\file.cshtml";
|
||||||
|
var projectPath = "C:\\path\\to\\project\\project.csproj";
|
||||||
|
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
|
||||||
|
var templateEngineFactoryService = GetTemplateEngineFactoryService();
|
||||||
|
|
||||||
|
uint cookie;
|
||||||
|
var fileChangeService = new Mock<IVsFileChangeEx>();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange(It.IsAny<string>(), It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK);
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.UnadviseFileChange(It.IsAny<uint>()))
|
||||||
|
.Returns(VSConstants.S_OK)
|
||||||
|
.Callback(() => throw new InvalidOperationException());
|
||||||
|
|
||||||
|
var manager = new DefaultImportDocumentManager(fileChangeService.Object, templateEngineFactoryService, Dispatcher, new DefaultErrorReporter());
|
||||||
|
manager.OnSubscribed(tracker); // Starts tracking import for the first document.
|
||||||
|
|
||||||
|
var anotherFilePath = "C:\\path\\to\\project\\anotherFile.cshtml";
|
||||||
|
var anotherTracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == anotherFilePath && t.ProjectPath == projectPath);
|
||||||
|
manager.OnSubscribed(anotherTracker); // Starts tracking import for the second document.
|
||||||
|
|
||||||
|
// Act & Assert (Does not throw)
|
||||||
|
manager.OnUnsubscribed(tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ForegroundTheory]
|
||||||
|
[InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Size, (int)ImportChangeKind.Changed)]
|
||||||
|
[InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Time, (int)ImportChangeKind.Changed)]
|
||||||
|
[InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Add, (int)ImportChangeKind.Added)]
|
||||||
|
[InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Del, (int)ImportChangeKind.Removed)]
|
||||||
|
public void OnFilesChanged_WithSpecificFlags_InvokesChangedHandler_WithExpectedArguments(uint fileChangeFlag, int expectedKind)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = "C:\\path\\to\\project\\file.cshtml";
|
||||||
|
var projectPath = "C:\\path\\to\\project\\project.csproj";
|
||||||
|
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
|
||||||
|
var templateEngineFactoryService = GetTemplateEngineFactoryService();
|
||||||
|
|
||||||
|
var anotherFilePath = "C:\\path\\to\\project\\anotherFile.cshtml";
|
||||||
|
var anotherTracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == anotherFilePath && t.ProjectPath == projectPath);
|
||||||
|
|
||||||
|
uint cookie;
|
||||||
|
var fileChangeService = new Mock<IVsFileChangeEx>();
|
||||||
|
fileChangeService
|
||||||
|
.Setup(f => f.AdviseFileChange(It.IsAny<string>(), It.IsAny<uint>(), It.IsAny<IVsFileChangeEvents>(), out cookie))
|
||||||
|
.Returns(VSConstants.S_OK);
|
||||||
|
var manager = new DefaultImportDocumentManager(fileChangeService.Object, templateEngineFactoryService, Dispatcher, new DefaultErrorReporter());
|
||||||
|
manager.OnSubscribed(tracker);
|
||||||
|
manager.OnSubscribed(anotherTracker);
|
||||||
|
|
||||||
|
var called = false;
|
||||||
|
manager.Changed += (sender, args) =>
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
Assert.Same(sender, manager);
|
||||||
|
Assert.Equal("C:\\path\\to\\project\\_ViewImports.cshtml", args.FilePath);
|
||||||
|
Assert.Equal((ImportChangeKind)expectedKind, args.Kind);
|
||||||
|
Assert.Collection(
|
||||||
|
args.AssociatedDocuments,
|
||||||
|
f => Assert.Equal(filePath, f),
|
||||||
|
f => Assert.Equal(anotherFilePath, f));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
manager.OnFilesChanged(fileCount: 1, filePaths: new[] { "C:\\path\\to\\project\\_ViewImports.cshtml" }, fileChangeFlags: new[] { fileChangeFlag });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(called);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RazorTemplateEngineFactoryService GetTemplateEngineFactoryService()
|
||||||
|
{
|
||||||
|
var projectManager = new Mock<ProjectSnapshotManager>();
|
||||||
|
projectManager.Setup(p => p.Projects).Returns(Array.Empty<ProjectSnapshot>());
|
||||||
|
|
||||||
|
var service = new DefaultTemplateEngineFactoryService(projectManager.Object);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue