Skip to content

Commit

Permalink
Fix #24
Browse files Browse the repository at this point in the history
  • Loading branch information
sboulema committed May 22, 2017
1 parent eb426b0 commit a3cdeda
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 118 deletions.
2 changes: 2 additions & 0 deletions CodeNav.Tests/CodeNav.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
<Compile Include="Files\TestNestedNamespaces.cs" />
<Compile Include="Files\TestNoNamespace.cs" />
<Compile Include="Files\TestProperties.cs" />
<Compile Include="Files\TestRegions.cs" />
<Compile Include="Files\TestSealed.cs" />
<Compile Include="Files\TestSwitch.cs" />
<Compile Include="Files\TestUsingsInNamespace.cs" />
<Compile Include="HelperTests\HighlightHelperTests.cs" />
<Compile Include="MapperTests\RegionMapperTests.cs" />
<Compile Include="MapperTests\TestEmptyInterface.cs" />
<Compile Include="MapperTests\TestInterface3.cs" />
<Compile Include="MapperTests\TestInterface2.cs" />
Expand Down
54 changes: 54 additions & 0 deletions CodeNav.Tests/Files/TestRegions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace CodeNav.Tests.Files
{
public class Class2
{
#region R1

#region R15
public const int nestedRegionConstant = 1;

#region R16
int i1 = 0;
#endregion

#endregion

public void Test1()
{
#region R11
int i1 = 0;
#endregion

#region R12
int i2 = 0;
#endregion

#region R13
int i3 = 0;
#endregion

#region R14
int i4 = 0;
#endregion
}

public void Test2()
{

}

#endregion

public void OutsideRegionFunction()
{

}

#region R2
public void SiblingRegionFunction()
{

}
#endregion
}
}
44 changes: 44 additions & 0 deletions CodeNav.Tests/MapperTests/RegionMapperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using CodeNav.Mappers;
using CodeNav.Models;
using NUnit.Framework;
using System;
using System.IO;
using System.Linq;

namespace CodeNav.Tests.MapperTests
{
[TestFixture]
public class RegionMapperTests
{
[Test]
public void TestRegions()
{
var document = SyntaxMapper.MapDocument(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\Files\\TestRegions.cs"));

Assert.IsTrue(document.Any());

// First item should be a namespace
Assert.AreEqual(CodeItemKindEnum.Namespace, document.First().Kind);

// There should be a single class
var regionClass = (document.First() as IMembers).Members.First() as CodeClassItem;
Assert.NotNull(regionClass);

// The class should have a function in it
Assert.NotNull(regionClass.Members.FirstOrDefault(m => m.Name.Equals("OutsideRegionFunction")));

// The class should have a region in it
var regionR1 = regionClass.Members.FirstOrDefault(m => m.Name.Equals("#R1")) as CodeRegionItem;
Assert.NotNull(regionR1);

// Region R1 should have a nested region R15 with a constant in it
var regionR15 = regionR1.Members.FirstOrDefault(m => m.Name.Equals("#R15")) as CodeRegionItem;
Assert.NotNull(regionR15);
Assert.NotNull(regionR15.Members.FirstOrDefault(m => m.Name.Equals("nestedRegionConstant")));

// Region R1 should have a function Test1 and Test2 in it
Assert.NotNull(regionR1.Members.FirstOrDefault(m => m.Name.Equals("Test1")));
Assert.NotNull(regionR1.Members.FirstOrDefault(m => m.Name.Equals("Test2")));
}
}
}
3 changes: 2 additions & 1 deletion CodeNav/CodeNav.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,15 @@
<Compile Include="FilterWindow.Designer.cs">
<DependentUpon>FilterWindow.cs</DependentUpon>
</Compile>
<Compile Include="Helpers\ColorHelper.cs" />
<Compile Include="Helpers\FindHelper.cs" />
<Compile Include="Helpers\HighlightHelper.cs" />
<Compile Include="Helpers\LogHelper.cs" />
<Compile Include="Helpers\OutliningHelper.cs" />
<Compile Include="Helpers\SortHelper.cs" />
<Compile Include="Helpers\VisibilityHelper.cs" />
<Compile Include="Mappers\FontStyleMapper.cs" />
<Compile Include="Mappers\RegionMapper.cs" />
<Compile Include="Mappers\StatementMapper.cs" />
<Compile Include="Mappers\SyntaxMapper.cs" />
<Compile Include="Mappers\TypeMapper.cs" />
Expand All @@ -116,7 +118,6 @@
<Compile Include="CodeViewUserControl.xaml.cs">
<DependentUpon>CodeViewUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\WidthMinusMarginConverter.cs" />
<Compile Include="Models\CodeRegionItem.cs" />
<Compile Include="Models\CodeClassItem.cs" />
<Compile Include="Models\CodeDocumentViewModel.cs" />
Expand Down
32 changes: 0 additions & 32 deletions CodeNav/Converters/WidthMinusMarginConverter.cs

This file was deleted.

14 changes: 14 additions & 0 deletions CodeNav/Helpers/ColorHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Windows.Media;

namespace CodeNav.Helpers
{
public static class ColorHelper
{
public static SolidColorBrush CreateSolidColorBrush(Color color)
{
var brush = new SolidColorBrush(color);
brush.Freeze();
return brush;
}
}
}
150 changes: 150 additions & 0 deletions CodeNav/Mappers/RegionMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using CodeNav.Helpers;
using CodeNav.Models;
using CodeNav.Properties;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;

namespace CodeNav.Mappers
{
public static class RegionMapper
{
public static List<CodeRegionItem> MapRegions(SyntaxTree tree, TextSpan span)
{
var root = tree.GetRoot();
var regionList = new List<CodeRegionItem>();

foreach (var regionDirective in root.DescendantTrivia().Where(i => i.Kind() == SyntaxKind.RegionDirectiveTrivia && span.Contains(i.Span)))
{
regionList.Add(MapRegion(regionDirective));
}

foreach (var endRegionDirective in root.DescendantTrivia().Where(j => j.Kind() == SyntaxKind.EndRegionDirectiveTrivia && span.Contains(j.Span)))
{
var reg = regionList.Last(x => x.StartLine < GetStartLine(endRegionDirective) && x.EndLine == 0);
reg.EndLine = GetEndLine(endRegionDirective);
}

var list = ToHierarchy(regionList, int.MinValue, int.MaxValue);

return list.Select(r => r as CodeRegionItem).ToList();
}

/// <summary>
/// Transform the flat list of Regions to a nested List based on the start and end lines of the items
/// </summary>
/// <param name="regionList"></param>
/// <param name="startLine"></param>
/// <param name="endLine"></param>
/// <returns></returns>
private static List<CodeItem> ToHierarchy(List<CodeRegionItem> regionList, int startLine, int endLine)
{
return (from r in regionList
where r.StartLine > startLine && r.EndLine < endLine &&
!regionList.Any(q => IsContainedWithin(r, q) && (startLine != int.MinValue ? q.EndLine - q.StartLine < endLine - startLine : true))
select new CodeRegionItem
{
Name = r.Name,
FullName = r.Name,
Id = r.Name,
Tooltip = r.Name,
StartLine = r.StartLine,
EndLine = r.EndLine,
Foreground = r.Foreground,
BorderBrush = r.BorderBrush,
FontSize = r.FontSize,
Kind = r.Kind,
Members = ToHierarchy(regionList, r.StartLine, r.EndLine)
}).ToList<CodeItem>();
}

private static CodeRegionItem MapRegion(SyntaxTrivia source)
{
var name = "#" + source.ToString().Replace("#region ", string.Empty);
return new CodeRegionItem
{
Name = name,
FullName = name,
Id = name,
Tooltip = name,
StartLine = GetStartLine(source),
Foreground = ColorHelper.CreateSolidColorBrush(Colors.Black),
BorderBrush = ColorHelper.CreateSolidColorBrush(Colors.DarkGray),
FontSize = Settings.Default.Font.SizeInPoints - 2,
Kind = CodeItemKindEnum.Region
};
}

/// <summary>
/// Add a CodeItem to the list of Regions, will recursively find the right region to add the item
/// </summary>
/// <param name="regions"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool AddToRegion(List<CodeRegionItem> regions, CodeItem item)
{
if (item?.StartLine == null) return false;

foreach (var region in regions)
{
if (region.Kind == CodeItemKindEnum.Region)
{
if (AddToRegion(region.Members, item))
{
return true;
}

if (item.StartLine >= region.StartLine && item.StartLine <= region.EndLine)
{
region.Members.Add(item);
return true;
}
}
}
return false;
}

/// <summary>
/// Help add a CodeItem to a inner Region structure
/// </summary>
/// <param name="members"></param>
/// <param name="item"></param>
/// <returns></returns>
private static bool AddToRegion(List<CodeItem> members, CodeItem item)
{
foreach (var member in members)
{
if (member is IMembers && AddToRegion((member as IMembers).Members, item))
{
return true;
}

if (member.Kind == CodeItemKindEnum.Region && IsContainedWithin(item, member))
{
(member as CodeRegionItem).Members.Add(item);
return true;
}
}

return false;
}

private static int GetStartLine(SyntaxTrivia source) =>
source.SyntaxTree.GetLineSpan(source.Span).StartLinePosition.Line + 1;

private static int GetEndLine(SyntaxTrivia source) =>
source.SyntaxTree.GetLineSpan(source.Span).EndLinePosition.Line + 1;

/// <summary>
/// Check if item 1 is contained within item 2
/// </summary>
/// <param name="r1">Smaller Item</param>
/// <param name="r2">Bigger Item</param>
/// <returns></returns>
private static bool IsContainedWithin(CodeItem r1, CodeItem r2) =>
r1.StartLine > r2.StartLine && r1.EndLine < r2.EndLine;
}
}
3 changes: 2 additions & 1 deletion CodeNav/Mappers/StatementMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CodeNav.Models;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using CodeNav.Helpers;

namespace CodeNav.Mappers
{
Expand All @@ -28,7 +29,7 @@ private static CodeItem MapSwitch(SwitchStatementSyntax statement)
item.Name = $"Switch {item.Name}";
item.Kind = CodeItemKindEnum.Switch;
item.Moniker = SyntaxMapper.MapMoniker(item.Kind, item.Access);
item.BorderBrush = SyntaxMapper.CreateSolidColorBrush(Colors.DarkGray);
item.BorderBrush = ColorHelper.CreateSolidColorBrush(Colors.DarkGray);
item.Tooltip = TooltipMapper.Map(item.Access, string.Empty, item.Name, item.Parameters);

// Map switch cases
Expand Down
Loading

0 comments on commit a3cdeda

Please sign in to comment.