Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################

**/obj/**
**/bin/**
.vs/CodeMetrics/v15/.suo
/.vs/CodeMetrics/v14/.suo
*.user
2 changes: 1 addition & 1 deletion CodeMetrics.Adornments/Adornments/ColorToBrushConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
{
if (value is Color)
{
Color color = (Color)value;
var color = (Color)value;
return new SolidColorBrush(color);
}

Expand Down
14 changes: 7 additions & 7 deletions CodeMetrics.Adornments/Adornments/ComplexityToColor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ public ComplexityToColor(IOptions options)

public Color Convert(int complexity)
{
var ratio = (Math.Min(complexity, MaximumComplexityThreshold))/ (double)MaximumComplexityThreshold;
Color maximumColor = ToMediaColor(this.options.BadColor);
Color minimumColor = ToMediaColor(this.options.GoodColor);
var ratio = (Math.Min(complexity, MaximumComplexityThreshold)) / (double)MaximumComplexityThreshold;
var maximumColor = ToMediaColor(this.options.BadColor);
var minimumColor = ToMediaColor(this.options.GoodColor);
return CombineColor(maximumColor, ratio, minimumColor);
}

private Color ToMediaColor(System.Drawing.Color source)
private static Color ToMediaColor(System.Drawing.Color source)
{
return Color.FromArgb(source.A, source.R, source.G, source.B);
}

private static Color CombineColor(Color color2, double ratio, Color color1)
{
return Color.FromRgb((byte)(color2.R*ratio + color1.R*(1D - ratio)),
(byte)(color2.G*ratio + color1.G*(1D - ratio)),
(byte)(color2.B*ratio + color1.B*(1D - ratio)));
return Color.FromRgb((byte)(color2.R * ratio + color1.R * (1D - ratio)),
(byte)(color2.G * ratio + color1.G * (1D - ratio)),
(byte)(color2.B * ratio + color1.B * (1D - ratio)));
}
}
}
66 changes: 66 additions & 0 deletions CodeMetrics.Adornments/Adornments/ExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using CodeMetrics.Parsing.Contracts;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

namespace CodeMetrics.Adornments
{
/// <summary>
/// Exception handler, to write message to the Output window
/// see http://stackoverflow.com/questions/1094366/how-do-i-write-to-the-visual-studio-output-window-in-my-custom-tool
/// </summary>
/// <seealso cref="IExceptionHandler" />
public class ExceptionHandler : IExceptionHandler
{
public void HandleException(Exception exception)
{
WriteToCodeMetricsOutputWindow(exception);
}

private static IVsOutputWindowPane GetCodeMetricsPane(IVsOutputWindow outWindow)
{
var customGuid = new Guid(GuidList.CodeMetricsOutputWindow);
outWindow.CreatePane(ref customGuid, "Code Metrics", 1, 1);

IVsOutputWindowPane customPane;
outWindow.GetPane(ref customGuid, out customPane);
return customPane;
}

private static IVsOutputWindowPane GetGeneralPane(IVsOutputWindow outWindow)
{
var generalPaneGuid = VSConstants.GUID_OutWindowGeneralPane;
IVsOutputWindowPane generalPane;
outWindow.GetPane(ref generalPaneGuid, out generalPane);
return generalPane;
}

private static void WriteExceptionToPane(Exception exception, IVsOutputWindowPane generalPane)
{
var outputString = string.Format("{0}{1}{0}{2}", Environment.NewLine, exception.Message,
exception.StackTrace);
generalPane.OutputString(outputString);
generalPane.Activate();
}

private void WriteToCodeMetricsOutputWindow(Exception exception)
{
var outWindow = GetOutputWindow();
var customPane = GetCodeMetricsPane(outWindow);
WriteExceptionToPane(exception, customPane);
}

private void WriteToGeneralOutputWindow(Exception exception)
{
var outWindow = GetOutputWindow();
var generalPane = GetGeneralPane(outWindow);
WriteExceptionToPane(exception, generalPane);
}

private static IVsOutputWindow GetOutputWindow()
{
return Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
}
}
}
12 changes: 6 additions & 6 deletions CodeMetrics.Adornments/Adornments/MeticsAdornmentFactory.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.ComponentModel.Composition;
using Castle.Windsor;
using CodeMetrics.Calculators;
using CodeMetrics.Calculators.Contracts;
using CodeMetrics.Common;
using CodeMetrics.Parsing;
using CodeMetrics.Parsing.Contracts;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;

Expand All @@ -23,11 +22,12 @@ internal sealed class MeticsAdornmentFactory : IWpfTextViewCreationListener

public void TextViewCreated(IWpfTextView textView)
{
WindsorContainer container = ContainerFactory.CreateContainer();
var exceptionHandler = new ExceptionHandler();
var container = ContainerFactory.CreateContainer(exceptionHandler);

var methodsExtractor = container.Resolve<IMethodsExtractor>();
var complexityCalculator = container.Resolve<IComplexityCalculator>();
new MetricsAdornment(textView, methodsExtractor, complexityCalculator);
var complexityCalculator = container.Resolve<ICyclomaticComplexityCalculator>();
var view = new MetricsAdornment(textView, methodsExtractor, complexityCalculator);
}
}
}
72 changes: 31 additions & 41 deletions CodeMetrics.Adornments/Adornments/MetricsAdornment.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using CodeMetrics.Calculators;
using CodeMetrics.Parsing;
using CodeMetrics.Calculators.Contracts;
using CodeMetrics.Parsing.Contracts;
using CodeMetrics.UserControls;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using System.Linq;

namespace CodeMetrics.Adornments
{
public class MetricsAdornment : IMetricsAdornment
{
readonly IAdornmentLayer layer;
readonly IWpfTextView view;
private readonly IAdornmentLayer layer;
private readonly IWpfTextView view;
private readonly IMethodsExtractor methodsExtractor;
private readonly IComplexityCalculator complexityCalculator;

private Dictionary<IMethod, string> methodToText;

private readonly ICyclomaticComplexityCalculator cyclomaticComplexityCalculator;
private readonly Options.Options options = new Options.Options();

public MetricsAdornment(IWpfTextView view, IMethodsExtractor methodsExtractor, IComplexityCalculator complexityCalculator)
private Dictionary<ISyntaxNode, ISyntaxNode> syntaxNodes;

public MetricsAdornment(IWpfTextView view, IMethodsExtractor methodsExtractor, ICyclomaticComplexityCalculator cyclomaticComplexityCalculator)
{
if (methodsExtractor == null) throw new ArgumentNullException(nameof(methodsExtractor));
if (cyclomaticComplexityCalculator == null) throw new ArgumentNullException(nameof(cyclomaticComplexityCalculator));

this.view = view;
layer = view.GetAdornmentLayer(MeticsAdornmentFactory.ADORNMENT_NAME);

this.view.LayoutChanged += OnLayoutChanged;
this.view.TextBuffer.PostChanged += OnTextBufferChanged;

this.methodsExtractor = methodsExtractor;
this.complexityCalculator = complexityCalculator;
this.cyclomaticComplexityCalculator = cyclomaticComplexityCalculator;

Init(view.TextSnapshot);
}
Expand All @@ -44,26 +46,10 @@ private void OnTextBufferChanged(object sender, EventArgs eventArgs)

private void Init(ITextSnapshot textSnapshot)
{
IEnumerable<IMethod> methods = methodsExtractor.Extract(textSnapshot.GetText())
.Where(method => method.BodyEnd.Line >= 0);

methodToText = methods.ToDictionary(method => method, method => GetText(textSnapshot, method));
}

private string GetText(ITextSnapshot textSnapshot, IMethod method)
{
return textSnapshot.GetText(GetMethodSpan(method));
}

private Span GetMethodSpan(IMethod method)
{
var startLine = view.TextSnapshot.GetLineFromLineNumber(method.BodyStart.Line);
var endLine = view.TextSnapshot.GetLineFromLineNumber(method.BodyEnd.Line);

int startPosition = startLine.Start.Position + method.BodyStart.Column;
int endPosition = endLine.Start.Position + method.BodyEnd.Column;
var methods = methodsExtractor.Extract(textSnapshot.GetText())
.OfType<ISyntaxNode>();

return Span.FromBounds(startPosition, endPosition);
syntaxNodes = methods.ToDictionary(method => method, method => method);
}

private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
Expand All @@ -80,9 +66,9 @@ private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)

private static bool IsVisibleAreaChanged(TextViewLayoutChangedEventArgs e)
{
ViewState newState = e.NewViewState;
ViewState oldState = e.OldViewState;
bool isVisibleAreaChanged = newState.ViewportBottom == oldState.ViewportBottom &&
var newState = e.NewViewState;
var oldState = e.OldViewState;
var isVisibleAreaChanged = newState.ViewportBottom == oldState.ViewportBottom &&
newState.ViewportHeight == oldState.ViewportHeight &&
newState.ViewportLeft == oldState.ViewportLeft &&
newState.ViewportRight == oldState.ViewportRight &&
Expand All @@ -96,29 +82,33 @@ private void RepaintComplexity(ITextSnapshot textSnapshot)
layer.RemoveAllAdornments();
options.LoadSettingsFromStorage();

foreach (var pair in methodToText)
foreach (var pair in syntaxNodes)
{
var geometry = view.TextViewLines.GetMarkerGeometry(textSnapshot.GetLineFromLineNumber(pair.Key.Decleration.Line).Extent);
var line = textSnapshot.GetLineFromLineNumber(pair.Key.Declaration.Line);
var geometry = view.TextViewLines.GetMarkerGeometry(line.Extent);
var isMethodVisible = geometry != null;
if (!isMethodVisible)
{
continue;
}

string methodText = methodToText[pair.Key];

var complexityViewModel = new ComplexityViewModel(options);
var complexityView = new ComplexityView
{
DataContext = complexityViewModel
};
new Task(() => complexityViewModel.UpdateComplexity(complexityCalculator.Calculate(methodText))).Start();
{
DataContext = complexityViewModel
};
CreateTask(complexityViewModel, pair.Key).Start();

Canvas.SetLeft(complexityView, geometry.Bounds.Left);
Canvas.SetTop(complexityView, geometry.Bounds.Top);

layer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, null, complexityView, null);
}
}

private Task CreateTask(ComplexityViewModel complexityViewModel, ISyntaxNode syntaxNode)
{
return new Task(() => complexityViewModel.UpdateComplexity(cyclomaticComplexityCalculator.Calculate(syntaxNode)));
}
}
}
Loading