Skip to content

Commit 98daf26

Browse files
authored
Merge pull request #180 from tonyhallett/colour-improvements
fix #179
2 parents e08ef4e + 6483558 commit 98daf26

14 files changed

+299
-96
lines changed

FineCodeCoverage/Core/FCCEngine.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ internal class FCCEngine : IFCCEngine
4141
private readonly ILogger logger;
4242
private readonly IAppDataFolder appDataFolder;
4343
private readonly IServiceProvider serviceProvider;
44+
4445
private IInitializeStatusProvider initializeStatusProvider;
4546
private readonly ICoverageToolOutputManager coverageOutputManager;
4647
internal System.Threading.Tasks.Task reloadCoverageTask;
@@ -71,7 +72,6 @@ IServiceProvider serviceProvider
7172
this.appDataFolder = appDataFolder;
7273
this.serviceProvider = serviceProvider;
7374
colorThemeService = serviceProvider.GetService(typeof(SVsColorThemeService));
74-
7575
}
7676

7777
internal string GetLogReloadCoverageStatusMessage(ReloadCoverageStatus reloadCoverageStatus)

FineCodeCoverage/FineCodeCoverage.csproj

+8-5
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<Compile Include="Core\Cobertura\Package.cs" />
6969
<Compile Include="Core\Cobertura\Packages.cs" />
7070
<Compile Include="Core\Cobertura\Sources.cs" />
71+
<Compile Include="Impl\CoverageColorProvider.cs" />
7172
<Compile Include="Core\CoverageToolOutput\AppOptionsCoverageToolOutputFolderSolutionProvider.cs" />
7273
<Compile Include="Core\CoverageToolOutput\CoverageToolOutputFolderFromSolutionProvider.cs" />
7374
<Compile Include="Core\CoverageToolOutput\FccOutputExistenceCoverageToolOutputFolderSolutionProvider.cs" />
@@ -81,6 +82,8 @@
8182
<Compile Include="Core\Coverlet\Console\CoverletConsoleCustomPathExecutor.cs" />
8283
<Compile Include="Core\Coverlet\Console\CoverletConsoleDotnetToolsLocalExecutor.cs" />
8384
<Compile Include="Core\CoverageToolOutput\ICoverageToolOutputManager.cs" />
85+
<Compile Include="Impl\ICoverageColours.cs" />
86+
<Compile Include="Impl\ICoverageColoursProvider.cs" />
8487
<Compile Include="Core\ICoverageUtilManager.cs" />
8588
<Compile Include="Core\MsTestPlatform\IMsTestPlatformUtil.cs" />
8689
<Compile Include="Core\Utilities\LinqExtensions.cs" />
@@ -153,9 +156,9 @@
153156
<Compile Include="Core\CoverageToolOutput\CoverageToolOutputManager.cs" />
154157
<Compile Include="Impl\ILogger.cs" />
155158
<Compile Include="Impl\RunSettingsRetriever.cs" />
156-
<Compile Include="Impl\GlyphFactory.cs" />
157-
<Compile Include="Impl\GlyphFactoryProvider.cs" />
158-
<Compile Include="Impl\GlyphTag.cs" />
159+
<Compile Include="Impl\CoverageLineGlyphFactory.cs" />
160+
<Compile Include="Impl\CoverageLineGlyphFactoryProvider.cs" />
161+
<Compile Include="Impl\CoverageLineGlyphTag.cs" />
159162
<Compile Include="Impl\Logger.cs" />
160163
<Compile Include="Impl\TestContainerDiscovery\Container.cs" />
161164
<Compile Include="Impl\TestContainerDiscovery\ContainerData.cs" />
@@ -173,8 +176,8 @@
173176
<Compile Include="Impl\TestContainerDiscovery\TestOperationFactory.cs" />
174177
<Compile Include="Impl\TestContainerDiscovery\TestRunResponse.cs" />
175178
<Compile Include="Impl\Vsix.cs" />
176-
<Compile Include="Impl\Tagger.cs" />
177-
<Compile Include="Impl\TaggerProvider.cs" />
179+
<Compile Include="Impl\CoverageLineGlyphTagger.cs" />
180+
<Compile Include="Impl\CoverageLineGlyphTaggerProvider.cs" />
178181
<Compile Include="Impl\TestContainerDiscovery\TestContainerDiscoverer.cs" />
179182
<Compile Include="Core\OpenCover\OpenCoverUtil.cs" />
180183
<Compile Include="Options\AppOptions.cs">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.ComponentModel.Composition;
3+
using FineCodeCoverage.Options;
4+
using Microsoft;
5+
using Microsoft.VisualStudio;
6+
using Microsoft.VisualStudio.Shell;
7+
using Microsoft.VisualStudio.Shell.Interop;
8+
9+
namespace FineCodeCoverage.Impl
10+
{
11+
[Export(typeof(ICoverageColoursProvider))]
12+
[Export(typeof(ICoverageColours))]
13+
internal class CoverageColorProvider : ICoverageColoursProvider, ICoverageColours
14+
{
15+
private readonly IVsFontAndColorStorage fontAndColorStorage;
16+
private Guid categoryWithCoverage = Guid.Parse("ff349800-ea43-46c1-8c98-878e78f46501");
17+
private uint storeFlags = (uint)(__FCSTORAGEFLAGS.FCSF_READONLY | __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS | __FCSTORAGEFLAGS.FCSF_NOAUTOCOLORS | __FCSTORAGEFLAGS.FCSF_PROPAGATECHANGES);
18+
private System.Windows.Media.Color defaultCoverageTouchedArea = System.Windows.Media.Colors.Green;
19+
private System.Windows.Media.Color defaultCoverageNotTouchedArea = System.Windows.Media.Colors.Red;
20+
private System.Windows.Media.Color defaultCoveragePartiallyTouchedArea = System.Windows.Media.Color.FromRgb(255, 165, 0);
21+
private System.Windows.Media.Color coverageTouchedArea;
22+
private System.Windows.Media.Color coverageNotTouchedArea;
23+
private System.Windows.Media.Color coveragePartiallyTouchedArea;
24+
public System.Windows.Media.Color CoverageTouchedArea {
25+
get {
26+
UpdateFromFontsAndColorsIfNecessary();
27+
return coverageTouchedArea;
28+
}
29+
private set
30+
{
31+
coverageTouchedArea = value;
32+
}
33+
}
34+
35+
public System.Windows.Media.Color CoverageNotTouchedArea {
36+
get
37+
{
38+
UpdateFromFontsAndColorsIfNecessary();
39+
return coverageNotTouchedArea;
40+
}
41+
private set
42+
{
43+
coverageNotTouchedArea = value;
44+
}
45+
}
46+
47+
public System.Windows.Media.Color CoveragePartiallyTouchedArea {
48+
get
49+
{
50+
UpdateFromFontsAndColorsIfNecessary();
51+
return coveragePartiallyTouchedArea;
52+
}
53+
private set
54+
{
55+
coveragePartiallyTouchedArea = value;
56+
}
57+
58+
}
59+
60+
private bool coverageColoursFromFontsAndColours;
61+
private bool requiresFromFontsAndColours;
62+
63+
[ImportingConstructor]
64+
public CoverageColorProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, IAppOptionsProvider appOptionsProvider)
65+
{
66+
ThreadHelper.ThrowIfNotOnUIThread();
67+
fontAndColorStorage = (IVsFontAndColorStorage)serviceProvider.GetService(typeof(IVsFontAndColorStorage));
68+
Assumes.Present(fontAndColorStorage);
69+
coverageColoursFromFontsAndColours = appOptionsProvider.Get().CoverageColoursFromFontsAndColours;
70+
UseDefaultColoursIfNotFontsAndColours();
71+
appOptionsProvider.OptionsChanged += AppOptionsProvider_OptionsChanged;
72+
}
73+
74+
private void AppOptionsProvider_OptionsChanged(IAppOptions appOptions)
75+
{
76+
coverageColoursFromFontsAndColours = appOptions.CoverageColoursFromFontsAndColours;
77+
UseDefaultColoursIfNotFontsAndColours();
78+
}
79+
80+
private void UseDefaultColoursIfNotFontsAndColours()
81+
{
82+
if (!coverageColoursFromFontsAndColours)
83+
{
84+
CoverageTouchedArea = defaultCoverageTouchedArea;
85+
CoverageNotTouchedArea = defaultCoverageNotTouchedArea;
86+
CoveragePartiallyTouchedArea = defaultCoveragePartiallyTouchedArea;
87+
}
88+
}
89+
90+
public void UpdateRequired()
91+
{
92+
requiresFromFontsAndColours = true;
93+
}
94+
95+
private void UpdateFromFontsAndColorsIfNecessary()
96+
{
97+
if(coverageColoursFromFontsAndColours && requiresFromFontsAndColours)
98+
{
99+
UpdateColoursFromFontsAndColors();
100+
}
101+
}
102+
103+
private void UpdateColoursFromFontsAndColors()
104+
{
105+
ThreadHelper.ThrowIfNotOnUIThread();
106+
var success = fontAndColorStorage.OpenCategory(ref categoryWithCoverage, storeFlags);
107+
if (success == VSConstants.S_OK)
108+
{
109+
CoverageTouchedArea = GetColor("Coverage Touched Area");
110+
CoverageNotTouchedArea = GetColor("Coverage Not Touched Area");
111+
CoveragePartiallyTouchedArea = GetColor("Coverage Partially Touched Area");
112+
}
113+
fontAndColorStorage.CloseCategory();
114+
//throw ?
115+
requiresFromFontsAndColours = false;
116+
}
117+
118+
private System.Windows.Media.Color GetColor(string displayName)
119+
{
120+
ThreadHelper.ThrowIfNotOnUIThread();
121+
var touchAreaInfo = new ColorableItemInfo[1];
122+
var getItemSuccess = fontAndColorStorage.GetItem(displayName, touchAreaInfo);
123+
if (getItemSuccess == VSConstants.S_OK)
124+
{
125+
return ParseColor(touchAreaInfo[0].crBackground);
126+
}
127+
throw new Exception("Failed to get color");
128+
}
129+
130+
private System.Windows.Media.Color ParseColor(uint color)
131+
{
132+
var dcolor = System.Drawing.ColorTranslator.FromOle(Convert.ToInt32(color));
133+
return System.Windows.Media.Color.FromArgb(dcolor.A, dcolor.R, dcolor.G, dcolor.B);
134+
}
135+
136+
137+
}
138+
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Windows;
2+
using System.Windows.Media;
3+
using System.Windows.Shapes;
4+
using Microsoft.VisualStudio.Text.Editor;
5+
using Microsoft.VisualStudio.Text.Formatting;
6+
7+
namespace FineCodeCoverage.Impl
8+
{
9+
internal class CoverageLineGlyphFactory : IGlyphFactory
10+
{
11+
private enum CoverageType { Covered, Partial, NotCovered}
12+
private ICoverageColours coverageColours;
13+
14+
public CoverageLineGlyphFactory(ICoverageColours coverageColours)
15+
{
16+
this.coverageColours = coverageColours;
17+
}
18+
19+
public UIElement GenerateGlyph(IWpfTextViewLine textViewLine, IGlyphTag glyphTag)
20+
{
21+
if (!(glyphTag is CoverageLineGlyphTag tag))
22+
{
23+
return null;
24+
}
25+
26+
// vars
27+
28+
var line = tag?.CoverageLine?.Line;
29+
var lineHitCount = line?.Hits ?? 0;
30+
var lineConditionCoverage = line?.ConditionCoverage?.Trim();
31+
32+
var coverageType = CoverageType.NotCovered;
33+
34+
if (lineHitCount > 0)
35+
{
36+
coverageType = CoverageType.Covered;
37+
38+
if (!string.IsNullOrWhiteSpace(lineConditionCoverage) && !lineConditionCoverage.StartsWith("100"))
39+
{
40+
coverageType = CoverageType.Partial;
41+
}
42+
}
43+
44+
// result
45+
46+
var result = new Rectangle();
47+
result.Width = 3;
48+
result.Height = 16;
49+
result.Fill = GetBrush(coverageType);
50+
// return
51+
52+
return result;
53+
}
54+
55+
private Brush GetBrush(CoverageType coverageType)
56+
{
57+
Color color = default;
58+
switch (coverageType)
59+
{
60+
case CoverageType.Partial:
61+
color = coverageColours.CoveragePartiallyTouchedArea;
62+
break;
63+
case CoverageType.NotCovered:
64+
color = coverageColours.CoverageNotTouchedArea;
65+
break;
66+
case CoverageType.Covered:
67+
color = coverageColours.CoverageTouchedArea;
68+
break;
69+
}
70+
return new SolidColorBrush(color);
71+
}
72+
}
73+
}

FineCodeCoverage/Impl/GlyphFactoryProvider.cs FineCodeCoverage/Impl/CoverageLineGlyphFactoryProvider.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@
66
namespace FineCodeCoverage.Impl
77
{
88
[ContentType("code")]
9-
[TagType(typeof(GlyphTag))]
9+
[TagType(typeof(CoverageLineGlyphTag))]
1010
[Order(Before = "VsTextMarker")]
1111
[Name(Vsix.GlyphFactoryProviderName)]
1212
[Export(typeof(IGlyphFactoryProvider))]
13-
internal class GlyphFactoryProvider: IGlyphFactoryProvider
13+
internal class CoverageLineGlyphFactoryProvider: IGlyphFactoryProvider
1414
{
15+
private readonly ICoverageColours coverageColours;
16+
17+
[ImportingConstructor]
18+
public CoverageLineGlyphFactoryProvider(ICoverageColours coverageColours)
19+
{
20+
this.coverageColours = coverageColours;
21+
}
1522
public IGlyphFactory GetGlyphFactory(IWpfTextView textView, IWpfTextViewMargin textViewMargin)
1623
{
17-
return new GlyphFactory();
24+
return new CoverageLineGlyphFactory(coverageColours);
1825
}
1926
}
2027
}

FineCodeCoverage/Impl/GlyphTag.cs FineCodeCoverage/Impl/CoverageLineGlyphTag.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
namespace FineCodeCoverage.Impl
55
{
6-
internal class GlyphTag : IGlyphTag
6+
internal class CoverageLineGlyphTag : IGlyphTag
77
{
88
public CoverageLine CoverageLine { get; }
99

10-
public GlyphTag(CoverageLine coverageLine)
10+
public CoverageLineGlyphTag(CoverageLine coverageLine)
1111
{
1212
CoverageLine = coverageLine;
1313
}

FineCodeCoverage/Impl/Tagger.cs FineCodeCoverage/Impl/CoverageLineGlyphTagger.cs

+11-9
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,33 @@
88

99
namespace FineCodeCoverage.Impl
1010
{
11-
internal class Tagger<T> : ITagger<T> where T : ITag
11+
internal class CoverageLineGlyphTagger : ITagger<CoverageLineGlyphTag>
1212
{
1313
private readonly ITextBuffer _textBuffer;
1414
private readonly IFCCEngine fccEngine;
15+
private readonly ICoverageColoursProvider coverageColoursProvider;
1516

16-
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
17+
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
1718

18-
public Tagger(ITextBuffer textBuffer,IFCCEngine fccEngine)
19+
public CoverageLineGlyphTagger(ITextBuffer textBuffer, IFCCEngine fccEngine, ICoverageColoursProvider coverageColoursProvider)
1920
{
2021
_textBuffer = textBuffer;
2122
this.fccEngine = fccEngine;
23+
this.coverageColoursProvider = coverageColoursProvider;
2224
fccEngine.UpdateMarginTags += FCCEngine_UpdateMarginTags;
2325
}
2426

2527
private void FCCEngine_UpdateMarginTags(UpdateMarginTagsEventArgs e)
2628
{
29+
coverageColoursProvider.UpdateRequired();
2730
var span = new SnapshotSpan(_textBuffer.CurrentSnapshot, 0, _textBuffer.CurrentSnapshot.Length);
2831
var spanEventArgs = new SnapshotSpanEventArgs(span);
2932
TagsChanged?.Invoke(this, spanEventArgs);
3033
}
3134

32-
IEnumerable<ITagSpan<T>> ITagger<T>.GetTags(NormalizedSnapshotSpanCollection spans)
35+
IEnumerable<ITagSpan<CoverageLineGlyphTag>> ITagger<CoverageLineGlyphTag>.GetTags(NormalizedSnapshotSpanCollection spans)
3336
{
34-
var result = new List<ITagSpan<T>>();
37+
var result = new List<ITagSpan<CoverageLineGlyphTag>>();
3538

3639
if (spans == null || fccEngine.CoverageLines == null)
3740
{
@@ -51,10 +54,9 @@ IEnumerable<ITagSpan<T>> ITagger<T>.GetTags(NormalizedSnapshotSpanCollection spa
5154

5255
foreach (var coverageLine in coverageLines)
5356
{
54-
var tag = new GlyphTag(coverageLine);
55-
var tagSpan = new TagSpan<GlyphTag>(span, tag);
56-
var iTagSpan = tagSpan as ITagSpan<T>;
57-
result.Add(iTagSpan);
57+
var tag = new CoverageLineGlyphTag(coverageLine);
58+
var tagSpan = new TagSpan<CoverageLineGlyphTag>(span, tag);
59+
result.Add(tagSpan);
5860
}
5961
}
6062

FineCodeCoverage/Impl/TaggerProvider.cs FineCodeCoverage/Impl/CoverageLineGlyphTaggerProvider.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@
77
namespace FineCodeCoverage.Impl
88
{
99
[ContentType("code")]
10-
[TagType(typeof(GlyphTag))]
10+
[TagType(typeof(CoverageLineGlyphTag))]
1111
[Name(Vsix.TaggerProviderName)]
1212
[Export(typeof(ITaggerProvider))]
13-
internal class TaggerProvider : ITaggerProvider
13+
internal class CoverageLineGlyphTaggerProvider : ITaggerProvider
1414
{
1515
private readonly IFCCEngine fccEngine;
16+
private readonly ICoverageColoursProvider coverageColoursProvider;
1617

1718
[ImportingConstructor]
18-
public TaggerProvider(IFCCEngine fccEngine)
19+
public CoverageLineGlyphTaggerProvider(IFCCEngine fccEngine, ICoverageColoursProvider coverageColoursProvider)
1920
{
2021
this.fccEngine = fccEngine;
22+
this.coverageColoursProvider = coverageColoursProvider;
2123
}
2224
public ITagger<T> CreateTagger<T>(ITextBuffer textBuffer) where T : ITag
2325
{
24-
return new Tagger<T>(textBuffer,fccEngine);
26+
return new CoverageLineGlyphTagger(textBuffer, fccEngine, coverageColoursProvider) as ITagger<T>;
2527
}
2628
}
2729
}

0 commit comments

Comments
 (0)