Skip to content

Commit

Permalink
Merge pull request #52145 from Cosifne/dev/shech/inheritanceMarginUI
Browse files Browse the repository at this point in the history
Inheritance Margin UI
  • Loading branch information
Cosifne authored Apr 2, 2021
2 parents 8dc8345 + 7f16273 commit c5ff0d1
Show file tree
Hide file tree
Showing 34 changed files with 1,141 additions and 125 deletions.
15 changes: 15 additions & 0 deletions src/EditorFeatures/Core.Wpf/EditorFeaturesWpfResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,19 @@
<data name="Interactive_host_process_platform" xml:space="preserve">
<value>Interactive host process platform</value>
</data>
<data name="Multiple_members_are_inherited" xml:space="preserve">
<value>Multiple members are inherited</value>
</data>
<data name="is_inherited" xml:space="preserve">
<value>is inherited</value>
</data>
<data name="Navigate_to_0" xml:space="preserve">
<value>Navigate to '{0}'</value>
</data>
<data name="_0_in_1" xml:space="preserve">
<value>'{0}' in '{1}'</value>
</data>
<data name="Multiple_members_are_inherited_on_line_0" xml:space="preserve">
<value>Multiple members are inherited on line {0}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,52 @@
// See the LICENSE file in the project root for more information.

using System.Windows;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.InheritanceMargin
{
internal sealed class InheritanceGlyphFactory : IGlyphFactory
{
private readonly IThreadingContext _threadingContext;
private readonly IStreamingFindUsagesPresenter _streamingFindUsagesPresenter;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly IWaitIndicator _waitIndicator;

public InheritanceGlyphFactory(
IThreadingContext threadingContext,
IStreamingFindUsagesPresenter streamingFindUsagesPresenter,
ClassificationTypeMap classificationTypeMap,
IClassificationFormatMap classificationFormatMap,
IWaitIndicator waitIndicator)
{
_threadingContext = threadingContext;
_streamingFindUsagesPresenter = streamingFindUsagesPresenter;
_classificationTypeMap = classificationTypeMap;
_classificationFormatMap = classificationFormatMap;
_waitIndicator = waitIndicator;
}

public UIElement? GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag)
{
// TODO: Add UI
if (tag is InheritanceMarginTag inheritanceMarginTag)
{
var membersOnLine = inheritanceMarginTag.MembersOnLine;
Contract.ThrowIfTrue(membersOnLine.IsEmpty);
return new MarginGlyph.InheritanceMargin(
_threadingContext,
_streamingFindUsagesPresenter,
_classificationTypeMap,
_classificationFormatMap,
_waitIndicator,
inheritanceMarginTag);
}

return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

using System;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
Expand All @@ -16,18 +19,35 @@ namespace Microsoft.CodeAnalysis.Editor.InheritanceMargin
[ContentType(ContentTypeNames.CSharpContentType)]
[ContentType(ContentTypeNames.VisualBasicContentType)]
[TagType(typeof(InheritanceMarginTag))]
[Order]
// This would ensure the margin is clickable.
[Order(After = "VsTextMarker")]
internal class InheritanceGlyphFactoryProvider : IGlyphFactoryProvider
{
private readonly IThreadingContext _threadingContext;
private readonly IStreamingFindUsagesPresenter _streamingFindUsagesPresenter;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly IWaitIndicator _waitIndicator;

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public InheritanceGlyphFactoryProvider()
public InheritanceGlyphFactoryProvider(
IThreadingContext threadingContext,
IStreamingFindUsagesPresenter streamingFindUsagesPresenter,
ClassificationTypeMap classificationTypeMap,
IClassificationFormatMapService classificationFormatMapService,
IWaitIndicator waitIndicator)
{
_threadingContext = threadingContext;
_streamingFindUsagesPresenter = streamingFindUsagesPresenter;
_classificationTypeMap = classificationTypeMap;
_classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap("tooltip");
_waitIndicator = waitIndicator;
}

public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin)
{
return new InheritanceGlyphFactory();
return new InheritanceGlyphFactory(_threadingContext, _streamingFindUsagesPresenter, _classificationTypeMap, _classificationFormatMap, _waitIndicator);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.InheritanceMargin;
using Microsoft.VisualStudio.Imaging;
using Microsoft.VisualStudio.Imaging.Interop;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.InheritanceMargin
{
internal static class InheritanceMarginHelpers
{
/// <summary>
/// Decide which moniker should be shown.
/// </summary>
public static ImageMoniker GetMoniker(InheritanceRelationship inheritanceRelationship)
{
// If there are multiple targets and we have the corresponding compound image, use it
if (inheritanceRelationship.HasFlag(InheritanceRelationship.ImplementingOverriding))
{
return KnownMonikers.ImplementingOverriding;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.ImplementingOverridden))
{
return KnownMonikers.ImplementingOverridden;
}

// Otherwise, show the image based on this preference
if (inheritanceRelationship.HasFlag(InheritanceRelationship.Implemented))
{
return KnownMonikers.Implemented;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Implementing))
{
return KnownMonikers.Implementing;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Overridden))
{
return KnownMonikers.Overridden;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Overriding))
{
return KnownMonikers.Overriding;
}

// The relationship is None. Don't know what image should be shown, throws
throw ExceptionUtilities.UnexpectedValue(inheritanceRelationship);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.InheritanceMargin;
using Microsoft.VisualStudio.Imaging;
using Microsoft.VisualStudio.Imaging.Interop;
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;
Expand All @@ -18,7 +16,7 @@ internal class InheritanceMarginTag : IGlyphTag
/// <summary>
/// Margin moniker.
/// </summary>
public readonly ImageMoniker Moniker;
public ImageMoniker Moniker { get; }

/// <summary>
/// Members needs to be shown on this line. There might be multiple members.
Expand All @@ -28,10 +26,19 @@ internal class InheritanceMarginTag : IGlyphTag
/// </summary>
public readonly ImmutableArray<InheritanceMarginItem> MembersOnLine;

public InheritanceMarginTag(ImmutableArray<InheritanceMarginItem> membersOnLine)
/// <summary>
/// Used for accessibility purpose.
/// </summary>
public readonly int LineNumber;

public readonly Workspace Workspace;

public InheritanceMarginTag(Workspace workspace, int lineNumber, ImmutableArray<InheritanceMarginItem> membersOnLine)
{
Contract.ThrowIfTrue(membersOnLine.IsEmpty);

Workspace = workspace;
LineNumber = lineNumber;
MembersOnLine = membersOnLine;
// The common case, one line has one member, avoid to use select & aggregate
if (membersOnLine.Length == 1)
Expand All @@ -44,57 +51,16 @@ public InheritanceMarginTag(ImmutableArray<InheritanceMarginItem> membersOnLine)
relationship |= target.RelationToMember;
}

Moniker = GetMoniker(relationship);
Moniker = InheritanceMarginHelpers.GetMoniker(relationship);
}
else
{
// Multiple members on same line.
var aggregateRelationship = membersOnLine
.SelectMany(member => member.TargetItems.Select(target => target.RelationToMember))
.Aggregate((r1, r2) => r1 | r2);
Moniker = GetMoniker(aggregateRelationship);
}
}

/// <summary>
/// Decide which moniker should be shown.
/// </summary>
private static ImageMoniker GetMoniker(InheritanceRelationship inheritanceRelationship)
{
// If there are multiple targets and we have the corresponding compound image, use it
if (inheritanceRelationship.HasFlag(InheritanceRelationship.ImplementingOverriding))
{
return KnownMonikers.ImplementingOverriding;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.ImplementingOverridden))
{
return KnownMonikers.ImplementingOverridden;
Moniker = InheritanceMarginHelpers.GetMoniker(aggregateRelationship);
}

// Otherwise, show the image based on this preference
if (inheritanceRelationship.HasFlag(InheritanceRelationship.Implemented))
{
return KnownMonikers.Implemented;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Implementing))
{
return KnownMonikers.Implementing;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Overridden))
{
return KnownMonikers.Overridden;
}

if (inheritanceRelationship.HasFlag(InheritanceRelationship.Overriding))
{
return KnownMonikers.Overriding;
}

// The relationship is None. Don't know what image should be shown, throws
throw ExceptionUtilities.UnexpectedValue(inheritanceRelationship);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ protected override async Task ProduceTagsAsync(
.GroupBy(item => item.LineNumber);

var snapshot = spanToTag.SnapshotSpan.Snapshot;

foreach (var (lineNumber, membersOnTheLine) in lineToMembers)
{
var membersOnTheLineArray = membersOnTheLine.ToImmutableArray();
Expand All @@ -129,7 +130,7 @@ protected override async Task ProduceTagsAsync(
// We only care about the line, so just tag the start.
context.AddTag(new TagSpan<InheritanceMarginTag>(
new SnapshotSpan(snapshot, line.Start, length: 0),
new InheritanceMarginTag(membersOnTheLineArray)));
new InheritanceMarginTag(document.Project.Solution.Workspace, lineNumber, membersOnTheLineArray)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.VisualStudio.Imaging.Interop;

namespace Microsoft.CodeAnalysis.Editor.InheritanceMargin.MarginGlyph
{
internal abstract class InheritanceContextMenuItemViewModel
{
/// <summary>
/// Display content for the target.
/// </summary>
public string DisplayContent { get; }

/// <summary>
/// ImageMoniker shown before the display name.
/// </summary>
public ImageMoniker ImageMoniker { get; }

/// <summary>
/// AutomationName for the MenuItem.
/// </summary>
public string AutomationName { get; }

protected InheritanceContextMenuItemViewModel(string displayContent, ImageMoniker imageMoniker, string automationName)
{
DisplayContent = displayContent;
ImageMoniker = imageMoniker;
AutomationName = automationName;
}
}
}
Loading

0 comments on commit c5ff0d1

Please sign in to comment.