Added necessary infrastructure for Tag helper project system imports
tracking
This commit is contained in:
parent
ece080466b
commit
90120f6a3b
|
|
@ -8,5 +8,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
ProjectChanged,
|
||||
EditorSettingsChanged,
|
||||
TagHelpersChanged,
|
||||
ImportsChanged,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// 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 Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
[System.Composition.Shared]
|
||||
[Export(typeof(RazorDocumentManager))]
|
||||
internal class DefaultRazorDocumentManager : RazorDocumentManager
|
||||
{
|
||||
private readonly RazorEditorFactoryService _editorFactoryService;
|
||||
private readonly TextBufferProjectService _projectService;
|
||||
|
||||
[ImportingConstructor]
|
||||
public DefaultRazorDocumentManager(
|
||||
RazorEditorFactoryService editorFactoryService,
|
||||
TextBufferProjectService projectService)
|
||||
{
|
||||
if (editorFactoryService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(editorFactoryService));
|
||||
}
|
||||
|
||||
if (projectService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectService));
|
||||
}
|
||||
|
||||
_editorFactoryService = editorFactoryService;
|
||||
_projectService = projectService;
|
||||
}
|
||||
|
||||
public override void OnTextViewOpened(ITextView textView, IList<ITextBuffer> subjectBuffers)
|
||||
{
|
||||
if (textView == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(textView));
|
||||
}
|
||||
|
||||
if (subjectBuffers == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(subjectBuffers));
|
||||
}
|
||||
|
||||
for (var i = 0; i < subjectBuffers.Count; i++)
|
||||
{
|
||||
var textBuffer = subjectBuffers[i];
|
||||
if (!textBuffer.IsRazorBuffer())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsSupportedProject(textBuffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_editorFactoryService.TryGetDocumentTracker(textBuffer, out var documentTracker) ||
|
||||
!(documentTracker is DefaultVisualStudioDocumentTracker tracker))
|
||||
{
|
||||
Debug.Fail("Tracker should always be available given our expectations of the VS workflow.");
|
||||
return;
|
||||
}
|
||||
|
||||
tracker.AddTextView(textView);
|
||||
|
||||
if (documentTracker.TextViews.Count == 1)
|
||||
{
|
||||
tracker.Subscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnTextViewClosed(ITextView textView, IList<ITextBuffer> subjectBuffers)
|
||||
{
|
||||
if (textView == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(textView));
|
||||
}
|
||||
|
||||
if (subjectBuffers == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(subjectBuffers));
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Notice that this method is called *after* changes are applied to the text buffer(s). We need to check every
|
||||
// one of them for a tracker because the content type could have changed.
|
||||
for (var i = 0; i < subjectBuffers.Count; i++)
|
||||
{
|
||||
var textBuffer = subjectBuffers[i];
|
||||
|
||||
DefaultVisualStudioDocumentTracker documentTracker;
|
||||
if (textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out documentTracker))
|
||||
{
|
||||
documentTracker.RemoveTextView(textView);
|
||||
|
||||
if (documentTracker.TextViews.Count == 0)
|
||||
{
|
||||
documentTracker.Unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSupportedProject(ITextBuffer textBuffer)
|
||||
{
|
||||
// Fundamentally we have a Razor half of the world as soon as the document is open - and then later
|
||||
// the C# half of the world will be initialized. This code is in general pretty tolerant of
|
||||
// unexpected /impossible states.
|
||||
//
|
||||
// We also want to successfully shut down if the buffer is something other than .cshtml.
|
||||
object project = null;
|
||||
var isSupportedProject = false;
|
||||
|
||||
// We expect the document to have a hierarchy even if it's not a real 'project'.
|
||||
// However the hierarchy can be null when the document is in the process of closing.
|
||||
if ((project = _projectService.GetHostProject(textBuffer)) != null)
|
||||
{
|
||||
isSupportedProject = _projectService.IsSupportedProject(project);
|
||||
}
|
||||
|
||||
return isSupportedProject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,35 +5,31 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Editor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
|
||||
{
|
||||
private readonly string _filePath;
|
||||
private readonly string _projectPath;
|
||||
private readonly ProjectSnapshotManager _projectManager;
|
||||
private readonly EditorSettingsManagerInternal _editorSettingsManager;
|
||||
private readonly TextBufferProjectService _projectService;
|
||||
private readonly ITextBuffer _textBuffer;
|
||||
private readonly List<ITextView> _textViews;
|
||||
private readonly Workspace _workspace;
|
||||
private bool _isSupportedProject;
|
||||
private ProjectSnapshot _project;
|
||||
private string _projectPath;
|
||||
|
||||
public override event EventHandler<ContextChangeEventArgs> ContextChanged;
|
||||
|
||||
public DefaultVisualStudioDocumentTracker(
|
||||
string filePath,
|
||||
string projectPath,
|
||||
ProjectSnapshotManager projectManager,
|
||||
TextBufferProjectService projectService,
|
||||
EditorSettingsManagerInternal editorSettingsManager,
|
||||
Workspace workspace,
|
||||
ITextBuffer textBuffer)
|
||||
|
|
@ -43,16 +39,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath));
|
||||
}
|
||||
|
||||
if (projectPath == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectPath));
|
||||
}
|
||||
|
||||
if (projectManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectManager));
|
||||
}
|
||||
|
||||
if (projectService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectService));
|
||||
}
|
||||
|
||||
if (editorSettingsManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(editorSettingsManager));
|
||||
|
|
@ -69,8 +65,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
}
|
||||
|
||||
_filePath = filePath;
|
||||
_projectPath = projectPath;
|
||||
_projectManager = projectManager;
|
||||
_projectService = projectService;
|
||||
_editorSettingsManager = editorSettingsManager;
|
||||
_textBuffer = textBuffer;
|
||||
_workspace = workspace; // For now we assume that the workspace is the always default VS workspace.
|
||||
|
|
@ -108,11 +104,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
if (!_textViews.Contains(textView))
|
||||
{
|
||||
_textViews.Add(textView);
|
||||
|
||||
if (_textViews.Count == 1)
|
||||
{
|
||||
Subscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,11 +117,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
if (_textViews.Contains(textView))
|
||||
{
|
||||
_textViews.Remove(textView);
|
||||
|
||||
if (_textViews.Count == 0)
|
||||
{
|
||||
Unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,42 +133,18 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
return null;
|
||||
}
|
||||
|
||||
private void Subscribe()
|
||||
public void Subscribe()
|
||||
{
|
||||
// Fundamentally we have a Razor half of the world as as soon as the document is open - and then later
|
||||
// the C# half of the world will be initialized. This code is in general pretty tolerant of
|
||||
// unexpected /impossible states.
|
||||
//
|
||||
// We also want to successfully shut down if the buffer is something other than .cshtml.
|
||||
IVsHierarchy hierarchy = null;
|
||||
string projectPath = null;
|
||||
var isSupportedProject = false;
|
||||
|
||||
if (_textBuffer.ContentType.IsOfType(RazorLanguage.ContentType) &&
|
||||
|
||||
// We expect the document to have a hierarchy even if it's not a real 'project'.
|
||||
// However the hierarchy can be null when the document is in the process of closing.
|
||||
(hierarchy = _projectService.GetHierarchy(_textBuffer)) != null)
|
||||
{
|
||||
projectPath = _projectService.GetProjectPath(hierarchy);
|
||||
isSupportedProject = _projectService.IsSupportedProject(hierarchy);
|
||||
}
|
||||
|
||||
if (!isSupportedProject || projectPath == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isSupportedProject = isSupportedProject;
|
||||
_projectPath = projectPath;
|
||||
_project = _projectManager.GetProjectWithFilePath(projectPath);
|
||||
_projectManager.Changed += ProjectManager_Changed;
|
||||
_editorSettingsManager.Changed += EditorSettingsManager_Changed;
|
||||
_projectManager.Changed += ProjectManager_Changed;
|
||||
|
||||
_isSupportedProject = true;
|
||||
_project = _projectManager.GetProjectWithFilePath(_projectPath);
|
||||
|
||||
OnContextChanged(_project, ContextChangeKind.ProjectChanged);
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
public void Unsubscribe()
|
||||
{
|
||||
_projectManager.Changed -= ProjectManager_Changed;
|
||||
_editorSettingsManager.Changed -= EditorSettingsManager_Changed;
|
||||
|
|
@ -190,6 +152,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
// Detached from project.
|
||||
_isSupportedProject = false;
|
||||
_project = null;
|
||||
|
||||
OnContextChanged(project: null, kind: ContextChangeKind.ProjectChanged);
|
||||
}
|
||||
|
||||
|
|
@ -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.Collections.Generic;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
internal abstract class RazorDocumentManager
|
||||
{
|
||||
public abstract void OnTextViewOpened(ITextView textView, IList<ITextBuffer> subjectBuffers);
|
||||
|
||||
public abstract void OnTextViewClosed(ITextView textView, IList<ITextBuffer> subjectBuffers);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +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 Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
internal abstract class TextBufferProjectService
|
||||
{
|
||||
public abstract IVsHierarchy GetHierarchy(ITextBuffer textBuffer);
|
||||
public abstract object GetHostProject(ITextBuffer textBuffer);
|
||||
|
||||
public abstract bool IsSupportedProject(IVsHierarchy hierarchy);
|
||||
public abstract bool IsSupportedProject(object project);
|
||||
|
||||
public abstract string GetProjectPath(object project);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
|
@ -41,7 +42,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
_documentTable = new RunningDocumentTable(services);
|
||||
}
|
||||
|
||||
public override IVsHierarchy GetHierarchy(ITextBuffer textBuffer)
|
||||
public override object GetHostProject(ITextBuffer textBuffer)
|
||||
{
|
||||
if (textBuffer == null)
|
||||
{
|
||||
|
|
@ -63,24 +64,27 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
return hierarchy;
|
||||
}
|
||||
|
||||
public override string GetProjectPath(IVsHierarchy hierarchy)
|
||||
public override string GetProjectPath(object project)
|
||||
{
|
||||
if (hierarchy == null)
|
||||
if (project == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hierarchy));
|
||||
throw new ArgumentNullException(nameof(project));
|
||||
}
|
||||
|
||||
var hierarchy = (IVsHierarchy)project;
|
||||
|
||||
ErrorHandler.ThrowOnFailure(((IVsProject)hierarchy).GetMkDocument((uint)VSConstants.VSITEMID.Root, out var path), VSConstants.E_NOTIMPL);
|
||||
return path;
|
||||
}
|
||||
|
||||
public override bool IsSupportedProject(IVsHierarchy hierarchy)
|
||||
public override bool IsSupportedProject(object project)
|
||||
{
|
||||
if (hierarchy == null)
|
||||
if (project == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hierarchy));
|
||||
throw new ArgumentNullException(nameof(project));
|
||||
}
|
||||
|
||||
var hierarchy = (IVsHierarchy)project;
|
||||
try
|
||||
{
|
||||
return hierarchy.IsCapabilityMatch(DotNetCoreCapability);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
}
|
||||
|
||||
var filePath = textDocument.FilePath;
|
||||
var tracker = new DefaultVisualStudioDocumentTracker(filePath, _projectManager, _projectService, _editorSettingsManager, _workspace, textBuffer);
|
||||
var project = _projectService.GetHostProject(textBuffer);
|
||||
if (project == null)
|
||||
{
|
||||
Debug.Fail("Text buffer should belong to a project.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var projectPath = _projectService.GetProjectPath(project);
|
||||
|
||||
var tracker = new DefaultVisualStudioDocumentTracker(filePath, projectPath, _projectManager, _editorSettingsManager, _workspace, textBuffer);
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,9 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
|
|
@ -22,69 +19,53 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
internal class RazorTextViewConnectionListener : IWpfTextViewConnectionListener
|
||||
{
|
||||
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||
private readonly TextBufferProjectService _projectService;
|
||||
private readonly RazorEditorFactoryService _editorFactoryService;
|
||||
private readonly Workspace _workspace;
|
||||
private readonly RazorDocumentManager _documentManager;
|
||||
|
||||
[ImportingConstructor]
|
||||
public RazorTextViewConnectionListener(
|
||||
TextBufferProjectService projectService,
|
||||
RazorEditorFactoryService editorFactoryService,
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace,
|
||||
RazorDocumentManager documentManager)
|
||||
{
|
||||
if (projectService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectService));
|
||||
}
|
||||
|
||||
if (editorFactoryService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(editorFactoryService));
|
||||
}
|
||||
|
||||
if (workspace == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspace));
|
||||
}
|
||||
|
||||
_projectService = projectService;
|
||||
_editorFactoryService = editorFactoryService;
|
||||
_workspace = workspace;
|
||||
if (documentManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentManager));
|
||||
}
|
||||
|
||||
_workspace = workspace;
|
||||
_documentManager = documentManager;
|
||||
_foregroundDispatcher = workspace.Services.GetRequiredService<ForegroundDispatcher>();
|
||||
}
|
||||
|
||||
// This is only for testing. We want to avoid using the actual Roslyn GetService methods in unit tests.
|
||||
internal RazorTextViewConnectionListener(
|
||||
ForegroundDispatcher foregroundDispatcher,
|
||||
TextBufferProjectService projectService,
|
||||
RazorEditorFactoryService editorFactoryService,
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||
Workspace workspace,
|
||||
RazorDocumentManager documentManager)
|
||||
{
|
||||
if (foregroundDispatcher == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||
}
|
||||
|
||||
if (projectService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectService));
|
||||
}
|
||||
|
||||
if (editorFactoryService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(editorFactoryService));
|
||||
}
|
||||
|
||||
if (workspace == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspace));
|
||||
}
|
||||
|
||||
if (documentManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentManager));
|
||||
}
|
||||
|
||||
_foregroundDispatcher = foregroundDispatcher;
|
||||
_projectService = projectService;
|
||||
_editorFactoryService = editorFactoryService;
|
||||
_workspace = workspace;
|
||||
_documentManager = documentManager;
|
||||
}
|
||||
|
||||
public Workspace Workspace => _workspace;
|
||||
|
|
@ -103,29 +84,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
|
||||
_foregroundDispatcher.AssertForegroundThread();
|
||||
|
||||
for (var i = 0; i < subjectBuffers.Count; i++)
|
||||
{
|
||||
var textBuffer = subjectBuffers[i];
|
||||
if (!textBuffer.IsRazorBuffer())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var hierarchy = _projectService.GetHierarchy(textBuffer);
|
||||
if (!_projectService.IsSupportedProject(hierarchy))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_editorFactoryService.TryGetDocumentTracker(textBuffer, out var documentTracker) ||
|
||||
!(documentTracker is DefaultVisualStudioDocumentTracker tracker))
|
||||
{
|
||||
Debug.Fail("Tracker should always be available given our expectations of the VS workflow.");
|
||||
return;
|
||||
}
|
||||
|
||||
tracker.AddTextView(textView);
|
||||
}
|
||||
_documentManager.OnTextViewOpened(textView, subjectBuffers);
|
||||
}
|
||||
|
||||
public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
|
||||
|
|
@ -142,21 +101,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
|
||||
_foregroundDispatcher.AssertForegroundThread();
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Notice that this method is called *after* changes are applied to the text buffer(s). We need to check every
|
||||
// one of them for a tracker because the content type could have changed.
|
||||
for (var i = 0; i < subjectBuffers.Count; i++)
|
||||
{
|
||||
var textBuffer = subjectBuffers[i];
|
||||
|
||||
DefaultVisualStudioDocumentTracker documentTracker;
|
||||
if (textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out documentTracker))
|
||||
{
|
||||
documentTracker.RemoveTextView(textView);
|
||||
}
|
||||
}
|
||||
_documentManager.OnTextViewClosed(textView, subjectBuffers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
// 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 Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||
{
|
||||
internal abstract class TextBufferProjectService
|
||||
{
|
||||
public abstract IVsHierarchy GetHierarchy(ITextBuffer textBuffer);
|
||||
|
||||
public abstract bool IsSupportedProject(IVsHierarchy hierarchy);
|
||||
|
||||
public abstract string GetProjectPath(IVsHierarchy hierarchy);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Editor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
public class DefaultRazorDocumentManagerTest
|
||||
{
|
||||
private IContentType RazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
|
||||
|
||||
private IContentType NonRazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(It.IsAny<string>()) == false);
|
||||
|
||||
private string FilePath => "C:/Some/Path/TestDocumentTracker.cshtml";
|
||||
|
||||
private string ProjectPath => "C:/Some/Path/TestProject.csproj";
|
||||
|
||||
private ProjectSnapshotManager ProjectManager => Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
|
||||
|
||||
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
|
||||
|
||||
private Workspace Workspace => new AdhocWorkspace();
|
||||
|
||||
private TextBufferProjectService SupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(
|
||||
s => s.GetHostProject(It.IsAny<ITextBuffer>()) == Mock.Of<object>() &&
|
||||
s.IsSupportedProject(It.IsAny<object>()) == true &&
|
||||
s.GetProjectPath(It.IsAny<object>()) == "C:/Some/Path/TestProject.csproj");
|
||||
|
||||
private TextBufferProjectService UnsupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<object>()) == false);
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewOpened_ForNonRazorCoreProject_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, UnsupportedProjectService);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
documentManager.OnTextViewOpened(textView, buffers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewOpened_ForNonRazorTextBuffer_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService.Object, SupportedProjectService);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
documentManager.OnTextViewOpened(textView, buffers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewOpened_ForRazorTextBuffer_AddsTextViewToTracker()
|
||||
{
|
||||
// Arrange
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
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 editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewOpened(textView, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewOpened_SubscribesAfterFirstTextViewOpened()
|
||||
{
|
||||
// Arrange
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && 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 editorFactoryService = Mock.Of<RazorEditorFactoryService>(f => f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
||||
|
||||
// Assert 1
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewOpened(textView, buffers);
|
||||
|
||||
// Assert 2
|
||||
Assert.True(documentTracker.IsSupportedProject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewClosed_FoNonRazorCoreProject_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), UnsupportedProjectService);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewClosed(textView, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var documentManager = new DefaultRazorDocumentManager(Mock.Of<RazorEditorFactoryService>(), SupportedProjectService);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewClosed(textView, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewClosed_ForAnyTextBufferWithTracker_RemovesTextView()
|
||||
{
|
||||
// Arrange
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// 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]);
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||
|
||||
documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[1]);
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||
|
||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewClosed(textView2, buffers);
|
||||
|
||||
// Assert
|
||||
documentTracker = buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1));
|
||||
|
||||
documentTracker = buffers[1].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextViewClosed_UnsubscribesAfterLastTextViewClosed()
|
||||
{
|
||||
// Arrange
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && 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]);
|
||||
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
|
||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
|
||||
var documentManager = new DefaultRazorDocumentManager(editorFactoryService, SupportedProjectService);
|
||||
|
||||
// Populate the text views
|
||||
documentTracker.Subscribe();
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
|
||||
// Act 1
|
||||
documentManager.OnTextViewClosed(textView2, buffers);
|
||||
|
||||
// Assert 1
|
||||
Assert.True(documentTracker.IsSupportedProject);
|
||||
|
||||
// Act
|
||||
documentManager.OnTextViewClosed(textView1, buffers);
|
||||
|
||||
// Assert 2
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,13 @@ using Microsoft.CodeAnalysis;
|
|||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Editor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
public class DefaultVisualStudioDocumentTrackerTest
|
||||
{
|
||||
|
|
@ -23,12 +22,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
|
||||
private string FilePath => "C:/Some/Path/TestDocumentTracker.cshtml";
|
||||
|
||||
private ProjectSnapshotManager ProjectManager => Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
|
||||
private string ProjectPath => "C:/Some/Path/TestProject.csproj";
|
||||
|
||||
private TextBufferProjectService ProjectService => Mock.Of<TextBufferProjectService>(
|
||||
s => s.GetHierarchy(It.IsAny<ITextBuffer>()) == Mock.Of<IVsHierarchy>() &&
|
||||
s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == true &&
|
||||
s.GetProjectPath(It.IsAny<IVsHierarchy>()) == "C:/Some/Path/TestProject.csproj");
|
||||
private ProjectSnapshotManager ProjectManager => Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
|
||||
|
||||
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
|
||||
|
||||
|
|
@ -38,11 +34,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
public void EditorSettingsManager_Changed_TriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var called = false;
|
||||
documentTracker.ContextChanged += (sender, args) =>
|
||||
{
|
||||
called = true;
|
||||
Assert.Equal(ContextChangeKind.EditorSettingsChanged, args.Kind);
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
@ -52,11 +49,55 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
Assert.True(called);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Subscribe_SetsSupportedProjectAndTriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var called = false;
|
||||
documentTracker.ContextChanged += (sender, args) =>
|
||||
{
|
||||
called = true;
|
||||
Assert.Equal(ContextChangeKind.ProjectChanged, args.Kind);
|
||||
};
|
||||
|
||||
// Act
|
||||
documentTracker.Subscribe();
|
||||
|
||||
// Assert
|
||||
Assert.True(called);
|
||||
Assert.True(documentTracker.IsSupportedProject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
|
||||
// Subscribe once to set supported project
|
||||
documentTracker.Subscribe();
|
||||
|
||||
var called = false;
|
||||
documentTracker.ContextChanged += (sender, args) =>
|
||||
{
|
||||
called = true;
|
||||
Assert.Equal(ContextChangeKind.ProjectChanged, args.Kind);
|
||||
};
|
||||
|
||||
// Act
|
||||
documentTracker.Unsubscribe();
|
||||
|
||||
// Assert
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
Assert.True(called);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTextView_AddsToTextViewCollection()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
|
||||
// Act
|
||||
|
|
@ -66,28 +107,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTextView_SubscribesAfterFirstTextViewAdded()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
|
||||
// Assert - 1
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
|
||||
// Act
|
||||
documentTracker.AddTextView(textView);
|
||||
|
||||
// Assert - 2
|
||||
Assert.True(documentTracker.IsSupportedProject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTextView_DoesNotAddDuplicateTextViews()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
|
||||
// Act
|
||||
|
|
@ -102,7 +126,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
public void AddTextView_AddsMultipleTextViewsToCollection()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
|
||||
|
|
@ -121,7 +145,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
public void RemoveTextView_RemovesTextViewFromCollection_SingleItem()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView = Mock.Of<ITextView>();
|
||||
documentTracker.AddTextView(textView);
|
||||
|
||||
|
|
@ -136,7 +160,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
public void RemoveTextView_RemovesTextViewFromCollection_MultipleItems()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
var textView3 = Mock.Of<ITextView>();
|
||||
|
|
@ -158,7 +182,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
public void RemoveTextView_NoopsWhenRemovingTextViewNotInCollection()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
documentTracker.AddTextView(textView1);
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
|
|
@ -169,28 +193,5 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
// Assert
|
||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveTextView_UnsubscribesAfterLastTextViewRemoved()
|
||||
{
|
||||
// Arrange
|
||||
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectManager, ProjectService, EditorSettingsManager, Workspace, TextBuffer);
|
||||
var textView1 = Mock.Of<ITextView>();
|
||||
var textView2 = Mock.Of<ITextView>();
|
||||
documentTracker.AddTextView(textView1);
|
||||
documentTracker.AddTextView(textView2);
|
||||
|
||||
// Act - 1
|
||||
documentTracker.RemoveTextView(textView1);
|
||||
|
||||
// Assert - 1
|
||||
Assert.True(documentTracker.IsSupportedProject);
|
||||
|
||||
// Act - 2
|
||||
documentTracker.RemoveTextView(textView2);
|
||||
|
||||
// Assert - 2
|
||||
Assert.False(documentTracker.IsSupportedProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.CodeAnalysis.Razor.Editor;
|
||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -19,149 +13,42 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
|||
{
|
||||
public class RazorTextViewConnectionListenerTest : ForegroundDispatcherTestBase
|
||||
{
|
||||
private ProjectSnapshotManager ProjectManager { get; } = Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
|
||||
|
||||
private TextBufferProjectService ProjectService { get; } = Mock.Of<TextBufferProjectService>(
|
||||
s => s.GetHierarchy(It.IsAny<ITextBuffer>()) == Mock.Of<IVsHierarchy>() &&
|
||||
s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == true &&
|
||||
s.GetProjectPath(It.IsAny<IVsHierarchy>()) == "C:/Some/Path/TestProject.csproj");
|
||||
|
||||
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
|
||||
|
||||
private Workspace Workspace { get; } = new AdhocWorkspace();
|
||||
|
||||
private IContentType RazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
|
||||
|
||||
private IContentType NonRazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(It.IsAny<string>()) == false);
|
||||
|
||||
private TextBufferProjectService SupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == true);
|
||||
|
||||
private TextBufferProjectService UnsupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == false);
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersConnected_ForNonRazorCoreProject_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||
var factory = new RazorTextViewConnectionListener(Dispatcher, UnsupportedProjectService, editorFactoryService.Object, Workspace);
|
||||
var textView = Mock.Of<IWpfTextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
}
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersConnected_ForNonRazorTextBuffer_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
|
||||
var factory = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, editorFactoryService.Object, Workspace);
|
||||
var textView = Mock.Of<IWpfTextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
}
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersConnected_ForRazorTextBuffer_AddsTextViewToTracker()
|
||||
public void SubjectBuffersConnected_CallsRazorDocumentManager_OnTextViewOpened()
|
||||
{
|
||||
// Arrange
|
||||
var textView = Mock.Of<IWpfTextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
VisualStudioDocumentTracker documentTracker = new DefaultVisualStudioDocumentTracker("AFile", ProjectManager, ProjectService, EditorSettingsManager, Workspace, buffers[0]);
|
||||
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
|
||||
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, editorFactoryService, Workspace);
|
||||
var buffers = new Collection<ITextBuffer>();
|
||||
var workspace = new AdhocWorkspace();
|
||||
var documentManager = new Mock<RazorDocumentManager>(MockBehavior.Strict);
|
||||
documentManager.Setup(d => d.OnTextViewOpened(textView, buffers)).Verifiable();
|
||||
|
||||
var listener = new RazorTextViewConnectionListener(Dispatcher, workspace, documentManager.Object);
|
||||
|
||||
// Act
|
||||
textViewListener.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
listener.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView));
|
||||
documentManager.Verify();
|
||||
}
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersDisconnected_ForAnyTextBufferWithTracker_RemovesTextView()
|
||||
public void SubjectBuffersDisonnected_CallsRazorDocumentManager_OnTextViewClosed()
|
||||
{
|
||||
// Arrange
|
||||
var textView1 = Mock.Of<IWpfTextView>();
|
||||
var textView2 = Mock.Of<IWpfTextView>();
|
||||
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
||||
var tracker = new DefaultVisualStudioDocumentTracker("C:/File/Path/To/Tracker1.cshtml", ProjectManager, ProjectService, EditorSettingsManager, Workspace, buffers[0]);
|
||||
tracker.AddTextView(textView1);
|
||||
tracker.AddTextView(textView2);
|
||||
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||
|
||||
tracker = new DefaultVisualStudioDocumentTracker("C:/File/Path/To/Tracker1.cshtml", ProjectManager, ProjectService, EditorSettingsManager, Workspace, buffers[1]);
|
||||
tracker.AddTextView(textView1);
|
||||
tracker.AddTextView(textView2);
|
||||
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
|
||||
|
||||
// Act
|
||||
textViewListener.SubjectBuffersDisconnected(textView2, ConnectionReason.BufferGraphChange, buffers);
|
||||
|
||||
// Assert
|
||||
tracker = buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView1));
|
||||
|
||||
tracker = buffers[1].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView1));
|
||||
}
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersDisconnected_FoNonRazorCoreProject_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, UnsupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
|
||||
var textView = Mock.Of<IWpfTextView>();
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
var buffers = new Collection<ITextBuffer>();
|
||||
var workspace = new AdhocWorkspace();
|
||||
var documentManager = new Mock<RazorDocumentManager>(MockBehavior.Strict);
|
||||
documentManager.Setup(d => d.OnTextViewClosed(textView, buffers)).Verifiable();
|
||||
|
||||
var listener = new RazorTextViewConnectionListener(Dispatcher, workspace, documentManager.Object);
|
||||
|
||||
// Act
|
||||
textViewListener.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
listener.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||
}
|
||||
|
||||
[ForegroundFact]
|
||||
public void SubjectBuffersDisconnected_ForAnyTextBufferWithoutTracker_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
|
||||
|
||||
var textView = Mock.Of<IWpfTextView>();
|
||||
|
||||
var buffers = new Collection<ITextBuffer>()
|
||||
{
|
||||
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||
};
|
||||
|
||||
// Act
|
||||
textViewListener.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||
|
||||
// Assert
|
||||
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||
documentManager.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue