Fixes #1632 - track textviews in the document tracker
I've stripped out some of the dead code and complexity from the document tracker in an attempt to simplify it. I will bring this back as part of the multi-targeting work.
This commit is contained in:
parent
8b4fc0cef6
commit
d87e0f7fbd
|
|
@ -1,21 +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 System;
|
|
||||||
using Microsoft.CodeAnalysis.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Razor
|
|
||||||
{
|
|
||||||
public abstract class RazorDocumentTracker
|
|
||||||
{
|
|
||||||
public abstract event EventHandler ContextChanged;
|
|
||||||
|
|
||||||
public abstract bool IsSupportedDocument { get; }
|
|
||||||
|
|
||||||
public abstract ProjectId ProjectId { get; }
|
|
||||||
|
|
||||||
public abstract SourceTextContainer TextContainer { get; }
|
|
||||||
|
|
||||||
public abstract Workspace Workspace { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.ObjectModel;
|
||||||
|
using Microsoft.VisualStudio.Text.Projection;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Text
|
||||||
|
{
|
||||||
|
internal static class BufferGraphExtensions
|
||||||
|
{
|
||||||
|
public static Collection<ITextBuffer> GetRazorBuffers(this IBufferGraph bufferGraph)
|
||||||
|
{
|
||||||
|
if (bufferGraph == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(bufferGraph));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufferGraph.GetTextBuffers(TextBufferExtensions.IsRazorBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,267 +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 System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
|
||||||
using Microsoft.CodeAnalysis.Text;
|
|
||||||
using Microsoft.VisualStudio.Text;
|
|
||||||
using Microsoft.VisualStudio.Text.Editor;
|
|
||||||
using Microsoft.VisualStudio.Text.Projection;
|
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|
||||||
{
|
|
||||||
internal class DefaultTextViewRazorDocumentTracker : RazorDocumentTracker
|
|
||||||
{
|
|
||||||
private readonly DefaultTextViewRazorDocumentTrackerService _service;
|
|
||||||
private readonly ITextView _textView;
|
|
||||||
|
|
||||||
private DocumentId _documentId;
|
|
||||||
private ITextBuffer _razorBuffer;
|
|
||||||
private bool _isSupportedProject;
|
|
||||||
private ITextBuffer _cSharpBuffer;
|
|
||||||
private SourceTextContainer _textContainer;
|
|
||||||
private Workspace _workspace;
|
|
||||||
private WorkspaceRegistration _workspaceRegistration;
|
|
||||||
|
|
||||||
public override event EventHandler ContextChanged;
|
|
||||||
|
|
||||||
public DefaultTextViewRazorDocumentTracker(DefaultTextViewRazorDocumentTrackerService service, ITextView textView)
|
|
||||||
{
|
|
||||||
if (service == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(service));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textView == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(textView));
|
|
||||||
}
|
|
||||||
|
|
||||||
_service = service;
|
|
||||||
_textView = textView;
|
|
||||||
|
|
||||||
Update();
|
|
||||||
|
|
||||||
_textView.Closed += TextView_Closed;
|
|
||||||
|
|
||||||
_textView.BufferGraph.GraphBufferContentTypeChanged += BufferGraph_GraphBufferContentTypeChanged;
|
|
||||||
_textView.BufferGraph.GraphBuffersChanged += BufferGraph_GraphBuffersChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsSupportedDocument => _isSupportedProject && _textContainer != null;
|
|
||||||
|
|
||||||
public override ProjectId ProjectId => _documentId?.ProjectId;
|
|
||||||
|
|
||||||
public override SourceTextContainer TextContainer => _textContainer;
|
|
||||||
|
|
||||||
public override Workspace Workspace => _workspace;
|
|
||||||
|
|
||||||
private bool Update()
|
|
||||||
{
|
|
||||||
// Update is called when the state of any of our surrounding systems changes. Here we want to examine the
|
|
||||||
// state of the world and then update properties as necessary.
|
|
||||||
//
|
|
||||||
// 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 when the buffer is renamed to something other .cshtml.
|
|
||||||
|
|
||||||
// If there's no Razor buffer, then there's really nothing to do. This isn't a Razor file.
|
|
||||||
var razorBuffer = _textView.BufferGraph.GetTextBuffers(IsRazorBuffer).FirstOrDefault();
|
|
||||||
|
|
||||||
// The source container is tied to the Razor buffer since that's what we want to watch for changes.
|
|
||||||
SourceTextContainer textContainer = null;
|
|
||||||
if (razorBuffer != null)
|
|
||||||
{
|
|
||||||
textContainer = razorBuffer.AsTextContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSupportedProject = false;
|
|
||||||
if (razorBuffer != null)
|
|
||||||
{
|
|
||||||
// The project can be null when the document is in the process of closing.
|
|
||||||
var project = _service.GetProject(razorBuffer);
|
|
||||||
|
|
||||||
if (project != null)
|
|
||||||
{
|
|
||||||
isSupportedProject = _service.IsSupportedProject(project);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The C# buffer is the other buffer in the graph that is C# (only if we already found a Razor buffer).
|
|
||||||
// We're not currently validating that it's a child of the Razor buffer even though we expect that.
|
|
||||||
ITextBuffer cSharpBuffer = null;
|
|
||||||
if (razorBuffer != null)
|
|
||||||
{
|
|
||||||
cSharpBuffer = _textView.BufferGraph.GetTextBuffers(IsCSharpBuffer).FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now if we have a C# buffer we want to watch for it be attached to a workspace.
|
|
||||||
SourceTextContainer cSharpTextContainer = null;
|
|
||||||
WorkspaceRegistration workspaceRegistration = null;
|
|
||||||
if (cSharpBuffer != null)
|
|
||||||
{
|
|
||||||
cSharpTextContainer = cSharpBuffer.AsTextContainer();
|
|
||||||
Debug.Assert(cSharpTextContainer != null);
|
|
||||||
|
|
||||||
workspaceRegistration = Workspace.GetWorkspaceRegistration(cSharpTextContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now finally we can see if we have a workspace
|
|
||||||
Workspace workspace = null;
|
|
||||||
if (workspaceRegistration != null)
|
|
||||||
{
|
|
||||||
workspace = workspaceRegistration.Workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we know if the Roslyn state for this document has been initialized, let's look for a project.
|
|
||||||
DocumentId documentId = null;
|
|
||||||
if (cSharpTextContainer != null && workspace != null)
|
|
||||||
{
|
|
||||||
documentId = workspace.GetDocumentIdInCurrentContext(cSharpTextContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// As a special case, we want to default to the VisualStudioWorkspace until we find out otherwise
|
|
||||||
// This lets us start working before a project gets initialized.
|
|
||||||
if (isSupportedProject && workspace == null)
|
|
||||||
{
|
|
||||||
workspace = _service.Workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
var changed = false;
|
|
||||||
changed |= razorBuffer == _razorBuffer;
|
|
||||||
changed |= textContainer == _textContainer;
|
|
||||||
changed |= isSupportedProject == _isSupportedProject;
|
|
||||||
changed |= cSharpBuffer == _cSharpBuffer;
|
|
||||||
changed |= workspaceRegistration == _workspaceRegistration;
|
|
||||||
changed |= workspace == _workspace;
|
|
||||||
changed |= documentId == _documentId;
|
|
||||||
|
|
||||||
// Now if nothing has changed we're all done!
|
|
||||||
if (!changed)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK, so something did change, let's commit the changes.
|
|
||||||
//
|
|
||||||
// These are all of the straightforward ones.
|
|
||||||
_razorBuffer = razorBuffer;
|
|
||||||
_textContainer = textContainer;
|
|
||||||
_isSupportedProject = isSupportedProject;
|
|
||||||
_cSharpBuffer = cSharpBuffer;
|
|
||||||
_documentId = documentId;
|
|
||||||
|
|
||||||
// Now these ones we subscribe to events so it's a little tricky.
|
|
||||||
if (_workspaceRegistration != null)
|
|
||||||
{
|
|
||||||
_workspaceRegistration.WorkspaceChanged -= WorkspaceRegistration_WorkspaceChanged;
|
|
||||||
}
|
|
||||||
if (workspaceRegistration != null)
|
|
||||||
{
|
|
||||||
workspaceRegistration.WorkspaceChanged += WorkspaceRegistration_WorkspaceChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_workspace != null)
|
|
||||||
{
|
|
||||||
_workspace.DocumentActiveContextChanged -= Workspace_DocumentActiveContextChanged;
|
|
||||||
}
|
|
||||||
if (workspace != null)
|
|
||||||
{
|
|
||||||
workspace.DocumentActiveContextChanged += Workspace_DocumentActiveContextChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
_workspaceRegistration = workspaceRegistration;
|
|
||||||
_workspace = workspace;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsCSharpBuffer(ITextBuffer textBuffer)
|
|
||||||
{
|
|
||||||
return textBuffer.ContentType.IsOfType("CSharp");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsRazorBuffer(ITextBuffer textBuffer)
|
|
||||||
{
|
|
||||||
return textBuffer.ContentType.IsOfType(RazorLanguage.ContentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BufferGraph_GraphBuffersChanged(object sender, GraphBuffersChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (Update())
|
|
||||||
{
|
|
||||||
OnContextChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BufferGraph_GraphBufferContentTypeChanged(object sender, GraphBufferContentTypeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (Update())
|
|
||||||
{
|
|
||||||
OnContextChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WorkspaceRegistration_WorkspaceChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (Update())
|
|
||||||
{
|
|
||||||
OnContextChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Workspace_DocumentActiveContextChanged(object sender, DocumentActiveContextChangedEventArgs e)
|
|
||||||
{
|
|
||||||
var textBuffer = e.SourceTextContainer.GetTextBuffer();
|
|
||||||
if (textBuffer != null && (textBuffer == _cSharpBuffer || textBuffer == _razorBuffer))
|
|
||||||
{
|
|
||||||
if (Update())
|
|
||||||
{
|
|
||||||
OnContextChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextView_Closed(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_textView.BufferGraph.GraphBufferContentTypeChanged -= BufferGraph_GraphBufferContentTypeChanged;
|
|
||||||
_textView.BufferGraph.GraphBuffersChanged -= BufferGraph_GraphBuffersChanged;
|
|
||||||
|
|
||||||
if (_workspaceRegistration != null)
|
|
||||||
{
|
|
||||||
_workspaceRegistration.WorkspaceChanged -= WorkspaceRegistration_WorkspaceChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_workspace != null)
|
|
||||||
{
|
|
||||||
_workspace.DocumentActiveContextChanged -= Workspace_DocumentActiveContextChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
_textView.Closed -= TextView_Closed;
|
|
||||||
|
|
||||||
_razorBuffer = null;
|
|
||||||
_textContainer = null;
|
|
||||||
_isSupportedProject = false;
|
|
||||||
_cSharpBuffer = null;
|
|
||||||
_workspaceRegistration = null;
|
|
||||||
_workspace = null;
|
|
||||||
_documentId = null;
|
|
||||||
|
|
||||||
OnContextChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnContextChanged()
|
|
||||||
{
|
|
||||||
var handler = ContextChanged;
|
|
||||||
if (handler != null)
|
|
||||||
{
|
|
||||||
handler(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +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 System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel.Composition;
|
|
||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
|
||||||
using Microsoft.VisualStudio.Shell;
|
|
||||||
using Microsoft.VisualStudio.Shell.Interop;
|
|
||||||
using Microsoft.VisualStudio.Text;
|
|
||||||
using Microsoft.VisualStudio.Text.Editor;
|
|
||||||
using Microsoft.VisualStudio.Utilities;
|
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|
||||||
{
|
|
||||||
[ContentType(RazorLanguage.ContentType)]
|
|
||||||
[TextViewRole(PredefinedTextViewRoles.Editable)]
|
|
||||||
[Export(typeof(IWpfTextViewConnectionListener))]
|
|
||||||
[Export(typeof(TextViewRazorDocumentTrackerService))]
|
|
||||||
internal class DefaultTextViewRazorDocumentTrackerService : TextViewRazorDocumentTrackerService, IWpfTextViewConnectionListener
|
|
||||||
{
|
|
||||||
private readonly ITextDocumentFactoryService _documentFactory;
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
private readonly Workspace _workspace;
|
|
||||||
|
|
||||||
private RunningDocumentTable _runningDocumentTable;
|
|
||||||
private IVsSolution _solution;
|
|
||||||
|
|
||||||
[ImportingConstructor]
|
|
||||||
public DefaultTextViewRazorDocumentTrackerService(
|
|
||||||
[Import(typeof(SVsServiceProvider))] IServiceProvider services,
|
|
||||||
ITextDocumentFactoryService documentFactory,
|
|
||||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
|
||||||
{
|
|
||||||
if (services == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(services));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (documentFactory == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(documentFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workspace == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(workspace));
|
|
||||||
}
|
|
||||||
|
|
||||||
_services = services;
|
|
||||||
_documentFactory = documentFactory;
|
|
||||||
_workspace = workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lazy to avoid needing this in unit tests.
|
|
||||||
private RunningDocumentTable RunningDocumentTable
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_runningDocumentTable == null)
|
|
||||||
{
|
|
||||||
_runningDocumentTable = new RunningDocumentTable(_services);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _runningDocumentTable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lazy to avoid needing this in unit tests.
|
|
||||||
private IVsSolution Solution
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_solution == null)
|
|
||||||
{
|
|
||||||
_solution = (IVsSolution)_services.GetService(typeof(SVsSolution));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _solution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Workspace Workspace => _workspace;
|
|
||||||
|
|
||||||
public override RazorDocumentTracker CreateTracker(ITextView textView)
|
|
||||||
{
|
|
||||||
if (textView == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(textView));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!textView.Properties.TryGetProperty<RazorDocumentTracker>(typeof(RazorDocumentTracker), out var tracker))
|
|
||||||
{
|
|
||||||
tracker = new DefaultTextViewRazorDocumentTracker(this, textView);
|
|
||||||
textView.Properties.AddProperty(typeof(RazorDocumentTracker), tracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tracker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SubjectBuffersConnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
|
|
||||||
{
|
|
||||||
if (textView == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(nameof(textView));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subjectBuffers == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(subjectBuffers));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This means a Razor buffer has been attached to this ITextView or the ITextView is just opening with Razor content.
|
|
||||||
//
|
|
||||||
// Call CreateTracker just for the side effect. The tracker will do all of the real work after it's initialized.
|
|
||||||
CreateTracker(textView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
|
|
||||||
{
|
|
||||||
if (textView == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(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.
|
|
||||||
//
|
|
||||||
// Do nothing, the tracker will update itself.
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IVsHierarchy GetProject(ITextBuffer textBuffer)
|
|
||||||
{
|
|
||||||
if (textBuffer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(textBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no document we can't find the FileName, or look for a matching hierarchy.
|
|
||||||
if (!_documentFactory.TryGetTextDocument(textBuffer, out var textDocument))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningDocumentTable.FindDocument(textDocument.FilePath, out var hierarchy, out uint itemId, out uint cookie);
|
|
||||||
|
|
||||||
// We don't currently try to look a Roslyn ProjectId at this point, we just want to know some
|
|
||||||
// basic things.
|
|
||||||
// See https://github.com/dotnet/roslyn/blob/4e3db2b7a0732d45a720e9ed00c00cd22ab67a14/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs#L47
|
|
||||||
// for a more complete implementation.
|
|
||||||
return hierarchy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool IsSupportedProject(IVsHierarchy project)
|
|
||||||
{
|
|
||||||
if (project == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(project));
|
|
||||||
}
|
|
||||||
|
|
||||||
return project.IsCapabilityMatch("DotNetCoreWeb");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<ITextView> GetTextViews(ITextBuffer textBuffer)
|
|
||||||
{
|
|
||||||
// TODO: Extract text views from buffer
|
|
||||||
|
|
||||||
return new[] { (ITextView)null };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// 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.ComponentModel.Composition;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.VisualStudio.Shell;
|
||||||
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
|
using Microsoft.VisualStudio.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Infrastructure methods to find project information from an <see cref="ITextBuffer"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Export(typeof(TextBufferProjectService))]
|
||||||
|
internal class DefaultTextBufferProjectService : TextBufferProjectService
|
||||||
|
{
|
||||||
|
private readonly RunningDocumentTable _documentTable;
|
||||||
|
private readonly ITextDocumentFactoryService _documentFactory;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public DefaultTextBufferProjectService(
|
||||||
|
[Import(typeof(SVsServiceProvider))] IServiceProvider services,
|
||||||
|
ITextDocumentFactoryService documentFactory,
|
||||||
|
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||||
|
{
|
||||||
|
if (services == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (documentFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(documentFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
_documentFactory = documentFactory;
|
||||||
|
_documentTable = new RunningDocumentTable(services);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IVsHierarchy GetHierarchy(ITextBuffer textBuffer)
|
||||||
|
{
|
||||||
|
if (textBuffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(textBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's no document we can't find the FileName, or look for a matching hierarchy.
|
||||||
|
if (!_documentFactory.TryGetTextDocument(textBuffer, out var textDocument))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_documentTable.FindDocument(textDocument.FilePath, out var hierarchy, out uint itemId, out uint cookie);
|
||||||
|
|
||||||
|
// We don't currently try to look a Roslyn ProjectId at this point, we just want to know some
|
||||||
|
// basic things.
|
||||||
|
// See https://github.com/dotnet/roslyn/blob/4e3db2b7a0732d45a720e9ed00c00cd22ab67a14/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs#L47
|
||||||
|
// for a more complete implementation.
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSupportedProject(IVsHierarchy hierarchy)
|
||||||
|
{
|
||||||
|
if (hierarchy == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(hierarchy));
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchy.IsCapabilityMatch("DotNetCoreWeb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
// 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 Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
|
using Microsoft.VisualStudio.Text;
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
|
||||||
|
{
|
||||||
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
private readonly ITextBuffer _textBuffer;
|
||||||
|
private readonly List<ITextView> _textViews;
|
||||||
|
|
||||||
|
private bool _isSupportedProject;
|
||||||
|
private Workspace _workspace;
|
||||||
|
|
||||||
|
public override event EventHandler ContextChanged;
|
||||||
|
|
||||||
|
public DefaultVisualStudioDocumentTracker(TextBufferProjectService projectService, Workspace workspace, ITextBuffer textBuffer)
|
||||||
|
{
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textBuffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(textBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
_projectService = projectService;
|
||||||
|
_textBuffer = textBuffer;
|
||||||
|
_workspace = workspace;
|
||||||
|
|
||||||
|
_textViews = new List<ITextView>();
|
||||||
|
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSupportedProject => _isSupportedProject;
|
||||||
|
|
||||||
|
public override ProjectId ProjectId => null;
|
||||||
|
|
||||||
|
public override ITextBuffer TextBuffer => _textBuffer;
|
||||||
|
|
||||||
|
public override IReadOnlyList<ITextView> TextViews => _textViews;
|
||||||
|
|
||||||
|
public IList<ITextView> TextViewsInternal => _textViews;
|
||||||
|
|
||||||
|
public override Workspace Workspace => _workspace;
|
||||||
|
|
||||||
|
private bool Update()
|
||||||
|
{
|
||||||
|
// Update is called when the state of any of our surrounding systems changes. Here we want to examine the
|
||||||
|
// state of the world and then update properties as necessary.
|
||||||
|
//
|
||||||
|
// 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 when the buffer is renamed to something other .cshtml.
|
||||||
|
IVsHierarchy project = null;
|
||||||
|
var isSupportedProject = false;
|
||||||
|
if (_textBuffer.ContentType.IsOfType(RazorLanguage.ContentType) &&
|
||||||
|
(project = _projectService.GetHierarchy(_textBuffer)) != null)
|
||||||
|
{
|
||||||
|
// 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.
|
||||||
|
isSupportedProject = _projectService.IsSupportedProject(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now we temporarily assume that the workspace is the default VS workspace.
|
||||||
|
var workspace = _workspace;
|
||||||
|
|
||||||
|
var changed = false;
|
||||||
|
changed |= isSupportedProject == _isSupportedProject;
|
||||||
|
changed |= workspace == _workspace;
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
_isSupportedProject = isSupportedProject;
|
||||||
|
_workspace = workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnContextChanged()
|
||||||
|
{
|
||||||
|
var handler = ContextChanged;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
// 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.ObjectModel;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Text;
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
using Microsoft.VisualStudio.Text.Projection;
|
||||||
|
using Microsoft.VisualStudio.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
[ContentType(RazorLanguage.ContentType)]
|
||||||
|
[TextViewRole(PredefinedTextViewRoles.Document)]
|
||||||
|
[Export(typeof(IWpfTextViewConnectionListener))]
|
||||||
|
[Export(typeof(VisualStudioDocumentTrackerFactory))]
|
||||||
|
internal class DefaultVisualStudioDocumentTrackerFactory : VisualStudioDocumentTrackerFactory, IWpfTextViewConnectionListener
|
||||||
|
{
|
||||||
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
private readonly Workspace _workspace;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public DefaultVisualStudioDocumentTrackerFactory(
|
||||||
|
TextBufferProjectService projectService,
|
||||||
|
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||||
|
{
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
_projectService = projectService;
|
||||||
|
_workspace = workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workspace Workspace => _workspace;
|
||||||
|
|
||||||
|
public override VisualStudioDocumentTracker GetTracker(ITextView textView)
|
||||||
|
{
|
||||||
|
if (textView == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(textView));
|
||||||
|
}
|
||||||
|
|
||||||
|
// While it's definitely possible to have multiple Razor text buffers attached to the same text view, there's
|
||||||
|
// no real scenario for it. This method always returns the tracker for the first Razor text buffer, but the
|
||||||
|
// other functionality for this class will maintain state correctly for the other buffers.
|
||||||
|
var textBuffer = textView.BufferGraph.GetRazorBuffers().FirstOrDefault();
|
||||||
|
if (textBuffer == null)
|
||||||
|
{
|
||||||
|
// No Razor buffer, nothing to track.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A little bit of hardening here, to make sure our assumptions are correct.
|
||||||
|
DefaultVisualStudioDocumentTracker tracker;
|
||||||
|
if (!textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out tracker))
|
||||||
|
{
|
||||||
|
Debug.Fail("The document tracker should be initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(tracker.TextViewsInternal.Contains(textView));
|
||||||
|
return tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SubjectBuffersConnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
|
||||||
|
{
|
||||||
|
if (textView == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultVisualStudioDocumentTracker tracker;
|
||||||
|
if (!textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out tracker))
|
||||||
|
{
|
||||||
|
tracker = new DefaultVisualStudioDocumentTracker(_projectService, _workspace, textBuffer);
|
||||||
|
textBuffer.Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tracker.TextViewsInternal.Contains(textView))
|
||||||
|
{
|
||||||
|
tracker.TextViewsInternal.Add(textView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
|
||||||
|
{
|
||||||
|
if (textView == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(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 tracker;
|
||||||
|
if (textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out tracker))
|
||||||
|
{
|
||||||
|
tracker.TextViewsInternal.Remove(textView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// 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 Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.VisualStudio.Text;
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
public abstract class VisualStudioDocumentTracker
|
||||||
|
{
|
||||||
|
public abstract event EventHandler ContextChanged;
|
||||||
|
|
||||||
|
public abstract bool IsSupportedProject { get; }
|
||||||
|
|
||||||
|
public abstract ProjectId ProjectId { get; }
|
||||||
|
|
||||||
|
public abstract Workspace Workspace { get; }
|
||||||
|
|
||||||
|
public abstract ITextBuffer TextBuffer { get; }
|
||||||
|
|
||||||
|
public abstract IReadOnlyList<ITextView> TextViews { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
public abstract class VisualStudioDocumentTrackerFactory
|
||||||
|
{
|
||||||
|
public abstract VisualStudioDocumentTracker GetTracker(ITextView textView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||||
using Microsoft.VisualStudio.Language.Intellisense;
|
using Microsoft.VisualStudio.Language.Intellisense;
|
||||||
using Microsoft.VisualStudio.Text;
|
using Microsoft.VisualStudio.Text;
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer;
|
using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
|
@ -145,7 +146,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
{
|
{
|
||||||
_foregroundThreadAffinitizedObject.AssertIsBackground();
|
_foregroundThreadAffinitizedObject.AssertIsBackground();
|
||||||
|
|
||||||
var textViews = DefaultTextViewRazorDocumentTrackerService.GetTextViews(_textBuffer);
|
var textViews = Array.Empty<ITextView>();
|
||||||
|
|
||||||
foreach (var textView in textViews)
|
foreach (var textView in textViews)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.EditorFeatures.Text" Version="$(RoslynDevVersion)" />
|
<PackageReference Include="Microsoft.CodeAnalysis.EditorFeatures.Text" Version="$(RoslynDevVersion)" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Editor" Version="$(VsShellVersion)" />
|
<PackageReference Include="Microsoft.VisualStudio.Editor" Version="$(VsShellVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="$(VsShellVersion)" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="$(RoslynDevVersion)" />
|
<PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="$(RoslynDevVersion)" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.LanguageServices.Razor.RemoteClient" Version="$(RoslynDevVersion)" />
|
<PackageReference Include="Microsoft.VisualStudio.LanguageServices.Razor.RemoteClient" Version="$(RoslynDevVersion)" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Text
|
||||||
|
{
|
||||||
|
internal static class TextBufferExtensions
|
||||||
|
{
|
||||||
|
public static bool IsRazorBuffer(this ITextBuffer textBuffer)
|
||||||
|
{
|
||||||
|
if (textBuffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(textBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return textBuffer.ContentType.IsOfType(RazorLanguage.ContentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
internal abstract class TextBufferProjectService
|
||||||
|
{
|
||||||
|
public abstract IVsHierarchy GetHierarchy(ITextBuffer textBuffer);
|
||||||
|
|
||||||
|
public abstract bool IsSupportedProject(IVsHierarchy hierarchy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +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.CodeAnalysis.Razor;
|
|
||||||
using Microsoft.VisualStudio.Text.Editor;
|
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|
||||||
{
|
|
||||||
public abstract class TextViewRazorDocumentTrackerService
|
|
||||||
{
|
|
||||||
public abstract RazorDocumentTracker CreateTracker(ITextView textView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
// 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.ObjectModel;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
|
using Microsoft.VisualStudio.Text;
|
||||||
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
using Microsoft.VisualStudio.Text.Projection;
|
||||||
|
using Microsoft.VisualStudio.Utilities;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
|
||||||
|
{
|
||||||
|
public class DefaultVisualStudioDocumentTrackerFactoryTest
|
||||||
|
{
|
||||||
|
private TextBufferProjectService ProjectService { get; } = Mock.Of<TextBufferProjectService>(
|
||||||
|
s => s.GetHierarchy(It.IsAny<ITextBuffer>()) == Mock.Of<IVsHierarchy>() &&
|
||||||
|
s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == true);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersConnected_ForNonRazorTextBuffer_DoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>();
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>()
|
||||||
|
{
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersConnected_ForRazorTextBufferWithoutTracker_CreatesTrackerAndTracksTextView()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>();
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>()
|
||||||
|
{
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var tracker = buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||||
|
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView));
|
||||||
|
Assert.Equal(buffers[0], tracker.TextBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersConnected_ForRazorTextBufferWithoutTracker_CreatesTrackerAndTracksTextView_ForMultipleBuffers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var textView = 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()),
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var tracker = buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||||
|
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView));
|
||||||
|
Assert.Equal(buffers[0], tracker.TextBuffer);
|
||||||
|
|
||||||
|
Assert.False(buffers[1].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||||
|
|
||||||
|
tracker = buffers[2].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker));
|
||||||
|
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView));
|
||||||
|
Assert.Equal(buffers[2], tracker.TextBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersConnected_ForRazorTextBufferWithTracker_DoesNotAddDuplicateTextViewEntry()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>();
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>()
|
||||||
|
{
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && 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(ProjectService, Workspace, buffers[0]);
|
||||||
|
tracker.TextViewsInternal.Add(textView);
|
||||||
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(tracker, buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker)));
|
||||||
|
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersConnected_ForRazorTextBufferWithTracker_AddsEntryForADifferentTextView()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
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()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
||||||
|
var tracker = new DefaultVisualStudioDocumentTracker(ProjectService, Workspace, buffers[0]);
|
||||||
|
tracker.TextViewsInternal.Add(textView1);
|
||||||
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersConnected(textView2, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(tracker, buffers[0].Properties.GetProperty<DefaultVisualStudioDocumentTracker>(typeof(VisualStudioDocumentTracker)));
|
||||||
|
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView1), v => Assert.Same(v, textView2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersDisconnected_ForAnyTextBufferWithTracker_RemovesTextView()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
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(ProjectService, Workspace, buffers[0]);
|
||||||
|
tracker.TextViewsInternal.Add(textView1);
|
||||||
|
tracker.TextViewsInternal.Add(textView2);
|
||||||
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
|
||||||
|
tracker = new DefaultVisualStudioDocumentTracker(ProjectService, Workspace, buffers[1]);
|
||||||
|
tracker.TextViewsInternal.Add(textView1);
|
||||||
|
tracker.TextViewsInternal.Add(textView2);
|
||||||
|
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.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));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubjectBuffersDisconnected_ForAnyTextBufferWithoutTracker_DoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>();
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>()
|
||||||
|
{
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
factory.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTracker_ForRazorTextBufferWithTracker_ReturnsTheFirstTracker()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>()
|
||||||
|
{
|
||||||
|
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var bufferGraph = Mock.Of<IBufferGraph>(g => g.GetTextBuffers(It.IsAny<Predicate<ITextBuffer>>()) == buffers);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>(v => v.BufferGraph == bufferGraph);
|
||||||
|
|
||||||
|
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
|
||||||
|
var tracker = new DefaultVisualStudioDocumentTracker(ProjectService, Workspace, buffers[0]);
|
||||||
|
tracker.TextViewsInternal.Add(textView);
|
||||||
|
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = factory.GetTracker(textView);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(tracker, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTracker_WithoutRazorBuffer_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var factory = new DefaultVisualStudioDocumentTrackerFactory(ProjectService, Workspace);
|
||||||
|
|
||||||
|
var buffers = new Collection<ITextBuffer>();
|
||||||
|
|
||||||
|
var bufferGraph = Mock.Of<IBufferGraph>(g => g.GetTextBuffers(It.IsAny<Predicate<ITextBuffer>>()) == buffers);
|
||||||
|
|
||||||
|
var textView = Mock.Of<IWpfTextView>(v => v.BufferGraph == bufferGraph);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = factory.GetTracker(textView);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net461</TargetFramework>
|
<TargetFramework>net461</TargetFramework>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
|
|
||||||
|
<!-- The binding redirects are needed due to a conflict between the test host and Roslyn regarding System.Collections.Immutable -->
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -22,6 +26,8 @@
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="$(RoslynDevVersion)" NoWarn="NU1605" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="$(RoslynDevVersion)" NoWarn="NU1605" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(RoslynDevVersion)" NoWarn="NU1605" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(RoslynDevVersion)" NoWarn="NU1605" />
|
||||||
|
|
||||||
|
<PackageReference Include="Moq" Version="$(MoqVersion)" />
|
||||||
|
|
||||||
<PackageReference Include="xunit.analyzers" Version="$(XunitAnalyzersVersion)" />
|
<PackageReference Include="xunit.analyzers" Version="$(XunitAnalyzersVersion)" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
||||||
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,15 @@ using System;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Host;
|
using Microsoft.CodeAnalysis.Host;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.VisualStudio.LanguageServices.Razor.Editor;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
{
|
{
|
||||||
public class RazorDocumentInfoViewModel : NotifyPropertyChanged
|
public class RazorDocumentInfoViewModel : NotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private readonly RazorDocumentTracker _documentTracker;
|
private readonly VisualStudioDocumentTracker _documentTracker;
|
||||||
|
|
||||||
public RazorDocumentInfoViewModel(RazorDocumentTracker documentTracker)
|
public RazorDocumentInfoViewModel(VisualStudioDocumentTracker documentTracker)
|
||||||
{
|
{
|
||||||
if (documentTracker == null)
|
if (documentTracker == null)
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
_documentTracker = documentTracker;
|
_documentTracker = documentTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSupportedDocument => _documentTracker.IsSupportedDocument;
|
public bool IsSupportedDocument => _documentTracker.IsSupportedProject;
|
||||||
|
|
||||||
public Project Project
|
public Project Project
|
||||||
{
|
{
|
||||||
|
|
@ -42,8 +42,6 @@ namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
|
|
||||||
public ProjectId ProjectId => _documentTracker.ProjectId;
|
public ProjectId ProjectId => _documentTracker.ProjectId;
|
||||||
|
|
||||||
public SourceTextContainer TextContainer => _documentTracker.TextContainer;
|
|
||||||
|
|
||||||
public Workspace Workspace => _documentTracker.Workspace;
|
public Workspace Workspace => _documentTracker.Workspace;
|
||||||
|
|
||||||
public HostLanguageServices RazorLanguageServices => Workspace?.Services.GetLanguageServices(RazorLanguage.Name);
|
public HostLanguageServices RazorLanguageServices => Workspace?.Services.GetLanguageServices(RazorLanguage.Name);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ using System.Windows;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.VisualStudio.ComponentModelHost;
|
using Microsoft.VisualStudio.ComponentModelHost;
|
||||||
using Microsoft.VisualStudio.Editor;
|
using Microsoft.VisualStudio.Editor;
|
||||||
using Microsoft.VisualStudio.LanguageServices.Razor;
|
using Microsoft.VisualStudio.LanguageServices.Razor.Editor;
|
||||||
using Microsoft.VisualStudio.Shell;
|
using Microsoft.VisualStudio.Shell;
|
||||||
using Microsoft.VisualStudio.Shell.Interop;
|
using Microsoft.VisualStudio.Shell.Interop;
|
||||||
using Microsoft.VisualStudio.Text.Editor;
|
using Microsoft.VisualStudio.Text.Editor;
|
||||||
|
|
@ -21,13 +21,13 @@ namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
internal class RazorDocumentInfoWindow : ToolWindowPane
|
internal class RazorDocumentInfoWindow : ToolWindowPane
|
||||||
{
|
{
|
||||||
private IVsEditorAdaptersFactoryService _adapterFactory;
|
private IVsEditorAdaptersFactoryService _adapterFactory;
|
||||||
private TextViewRazorDocumentTrackerService _documentTrackerService;
|
private VisualStudioDocumentTrackerFactory _documentTrackerService;
|
||||||
private IVsTextManager _textManager;
|
private IVsTextManager _textManager;
|
||||||
private IVsRunningDocumentTable _rdt;
|
private IVsRunningDocumentTable _rdt;
|
||||||
|
|
||||||
private uint _cookie;
|
private uint _cookie;
|
||||||
private ITextView _textView;
|
private ITextView _textView;
|
||||||
private RazorDocumentTracker _documentTracker;
|
private VisualStudioDocumentTracker _documentTracker;
|
||||||
|
|
||||||
public RazorDocumentInfoWindow()
|
public RazorDocumentInfoWindow()
|
||||||
: base(null)
|
: base(null)
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
|
|
||||||
var component = (IComponentModel)GetService(typeof(SComponentModel));
|
var component = (IComponentModel)GetService(typeof(SComponentModel));
|
||||||
_adapterFactory = component.GetService<IVsEditorAdaptersFactoryService>();
|
_adapterFactory = component.GetService<IVsEditorAdaptersFactoryService>();
|
||||||
_documentTrackerService = component.GetService<TextViewRazorDocumentTrackerService>();
|
_documentTrackerService = component.GetService<VisualStudioDocumentTrackerFactory>();
|
||||||
|
|
||||||
_textManager = (IVsTextManager)GetService(typeof(SVsTextManager));
|
_textManager = (IVsTextManager)GetService(typeof(SVsTextManager));
|
||||||
_rdt = (IVsRunningDocumentTable)GetService(typeof(SVsRunningDocumentTable));
|
_rdt = (IVsRunningDocumentTable)GetService(typeof(SVsRunningDocumentTable));
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.VisualStudio.RazorExtension.DocumentInfo
|
||||||
_documentTracker.ContextChanged -= DocumentTracker_ContextChanged;
|
_documentTracker.ContextChanged -= DocumentTracker_ContextChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
_documentTracker = _documentTrackerService.CreateTracker(textView);
|
_documentTracker = _documentTrackerService.GetTracker(textView);
|
||||||
_documentTracker.ContextChanged += DocumentTracker_ContextChanged;
|
_documentTracker.ContextChanged += DocumentTracker_ContextChanged;
|
||||||
|
|
||||||
((FrameworkElement)Content).DataContext = new RazorDocumentInfoViewModel(_documentTracker);
|
((FrameworkElement)Content).DataContext = new RazorDocumentInfoViewModel(_documentTracker);
|
||||||
|
|
|
||||||
|
|
@ -19,34 +19,13 @@
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Label Grid.Column="0" Grid.Row="0" Content="Project"/>
|
<Label Grid.Column="0" Grid.Row="0" Content="Project"/>
|
||||||
<Label Grid.Column="1" Grid.Row="0" Content="{Binding Project.Name}"/>
|
<Label Grid.Column="1" Grid.Row="0" Content="{Binding Project.Name}"/>
|
||||||
<Label Grid.Column="0" Grid.Row="1" Content="Is Supported"/>
|
<Label Grid.Column="0" Grid.Row="1" Content="Is Supported"/>
|
||||||
<Label Grid.Column="1" Grid.Row="1" Content="{Binding IsSupportedDocument}"/>
|
<Label Grid.Column="1" Grid.Row="1" Content="{Binding IsSupportedDocument}"/>
|
||||||
<Label Grid.Column="0" Grid.Row="2" Content="Text Container"/>
|
<Label Grid.Column="0" Grid.Row="2" Content="Workspace"/>
|
||||||
<Label Grid.Column="1" Grid.Row="2" Content="{Binding TextContainer}"/>
|
<Label Grid.Column="1" Grid.Row="2" Content="{Binding Workspace}"/>
|
||||||
<Label Grid.Column="0" Grid.Row="3" Content="Workspace"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="3" Content="{Binding Workspace}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="4" Content="Razor Lang"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="4" Content="{Binding RazorLanguageServices}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="5" Content="Resolver"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="5" Content="{Binding TagHelperResolver}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="6" Content="Syntax Facts"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="6" Content="{Binding RazorSyntaxFactsService}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="7" Content="Template Eng"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="7" Content="{Binding RazorTemplateEngineFactoryService}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="8" Content="Completion Service"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="8" Content="{Binding TagHelperCompletionService}"/>
|
|
||||||
<Label Grid.Column="0" Grid.Row="9" Content="TH Facts"/>
|
|
||||||
<Label Grid.Column="1" Grid.Row="9" Content="{Binding TagHelperFactsService}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VsixVersion>15.5</VsixVersion>
|
<VsixVersion>15.5</VsixVersion>
|
||||||
<VsixVersion Condition="'$(BuildNumber)'!=''">$(VsixVersion).$(BuildNumber)</VsixVersion>
|
<VsixVersion Condition="'$(BuildNumber)'!=''">$(VsixVersion).$(BuildNumber)</VsixVersion>
|
||||||
|
<VsixVersion Condition="'$(BuildNumber)'==''">$(VsixVersion).999999</VsixVersion>
|
||||||
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue