Permalink
Browse files

Make breakpoints persistent per assembly list

  • Loading branch information...
1 parent 8b62c90 commit 6b7215361e588fd0570f142015c6b0f9af5762f6 @RKlier committed Sep 17, 2011
@@ -86,6 +86,7 @@
<Compile Include="Models\TreeModel\StackFrameNode.cs" />
<Compile Include="Models\TreeModel\TreeNode.cs" />
<Compile Include="Models\TreeModel\Utils.cs" />
+ <Compile Include="Services\BreakpointService.cs" />
<Compile Include="Services\Debugger\DebuggerHelper.cs" />
<Compile Include="Services\Debugger\ListHelper.cs" />
<Compile Include="Services\Debugger\TypeResolverExtension.cs" />
@@ -105,11 +106,11 @@
<DependentUpon>AttachToProcessWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
- <Compile Include="UI\BreakpointPanel.xaml.cs" >
+ <Compile Include="UI\BreakpointPanel.xaml.cs">
<DependentUpon>BreakpointPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
- <Compile Include="UI\CallStackPanel.xaml.cs" >
+ <Compile Include="UI\CallStackPanel.xaml.cs">
<DependentUpon>CallStackPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
@@ -122,12 +123,7 @@
<SubType>Code</SubType>
</Compile>
</ItemGroup>
- <ItemGroup>
- <Folder Include="Images" />
- <Folder Include="Models\TreeModel" />
- <Folder Include="Commands" />
- <Folder Include="ToolTips" />
- </ItemGroup>
+ <ItemGroup />
<ItemGroup>
<Page Include="ToolTips\DebuggerTooltipControl.xaml" />
<Page Include="ToolTips\PinControlsDictionary.xaml" />
@@ -0,0 +1,160 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+#region using
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.Specialized;
+using ICSharpCode.ILSpy.Bookmarks;
+using System.Xml.Linq;
+using ICSharpCode.ILSpy.Debugger.Bookmarks;
+using ICSharpCode.ILSpy.XmlDoc;
+using Mono.Cecil;
+using ICSharpCode.Decompiler.ILAst;
+using ICSharpCode.NRefactory.CSharp;
+
+#endregion
+
+namespace ICSharpCode.ILSpy.Debugger.Services
+{
+ [ExportBookmarkPersistenceAttribute(SupportedType=typeof(BreakpointBookmark))]
+ public class BreakpointPersistence : IBookmarkPersistence
+ {
+ #region IBookmarkPersistence Members
+
+ public XElement Save(BookmarkBase bookmark)
+ {
+ var b = bookmark as BreakpointBookmark;
+ XElement bElement = new XElement("Bookmark",
+ new XAttribute("functionToken", b.FunctionToken),
+ new XAttribute("isProperty", b.FunctionToken != b.MemberReference.MetadataToken.ToInt32()),
+ new XAttribute("enabled", b.IsEnabled),
+ new XAttribute("ilRange", b.ILRange),
+ new XAttribute("assembly", b.MemberReference.Module.FullyQualifiedName),
+ new XAttribute("type", b.MemberReference.DeclaringType.FullName),
+ new XAttribute("method", b.MemberReference.Name),
+ new XAttribute("line", b.LineNumber)); // line number is just stored as an initial value (it will be adapted if the method is decompiled/shown)
+ return bElement;
+ }
+
+ public BookmarkBase Load(XElement bookmarkNode)
+ {
+ string assembly = (string)bookmarkNode.Attribute("assembly");
+ string type = (string)bookmarkNode.Attribute("type");
+ string method = (string)bookmarkNode.Attribute("method");
+ MemberReference mr = BreakpointService.ResolveMethod(assembly, type + "." + method);
+ if (mr == null)
+ return null;
+ ILRange range;
+ int functionToken;
+ int line;
+ if (!ILRange.TryParse((string)bookmarkNode.Attribute("ilRange"), out range)
+ || !int.TryParse((string)bookmarkNode.Attribute("functionToken"), out functionToken)
+ || !int.TryParse((string)bookmarkNode.Attribute("line"), out line))
+ return null;
+ var breakpoint = new BreakpointBookmark(mr, new AstLocation(line, 0), functionToken, range,
+ BreakpointAction.Break, DebugInformation.Language);
+ breakpoint.IsEnabled = (bool)bookmarkNode.Attribute("enabled");
+ return breakpoint;
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Store and load the bookmarks.
+ /// </summary>
+ /// <remarks>
+ /// This task should be handled by BookmarkManager, but it could not reach IlSpySettings and MainWindow.
+ /// </remarks>
+ static class BreakpointService
+ {
+ static string activeAssemblyListName = null;
+
+ public static void Initialize()
+ {
+ BookmarkManager.PersistenceEntries =
+ App.CompositionContainer.GetExports<IBookmarkPersistence, IBookmarkPersistenceMetadata>();
+ if (MainWindow.Instance.CurrentAssemblyList != null)
+ {
+ activeAssemblyListName = MainWindow.Instance.CurrentAssemblyList.ListName;
+ LoadBookmarks();
+ }
+ MainWindow.Instance.CurrentAssemblyListChanged += OnCurrentAssemblyListChanged;
+ MainWindow.Instance.Closing += delegate
+ {
+ SaveBookmarks();
+ MainWindow.Instance.CurrentAssemblyListChanged -= OnCurrentAssemblyListChanged;
+ };
+
+ }
+
+ public static MemberReference ResolveMethod(string assembly, string fullMethodName)
+ {
+ var foundAssembly = MainWindow.Instance.CurrentAssemblyList.OpenAssembly(assembly);
+ if (null == foundAssembly)
+ return null;
+ if (!foundAssembly.IsLoaded)
+ foundAssembly.WaitUntilLoaded();
+ // Replace is done because XmlDocKeyProvider stores ".ctor" as "#ctor"
+ MemberReference mr =
+ XmlDocKeyProvider.FindMemberByKey(foundAssembly.AssemblyDefinition.MainModule, "M:" + fullMethodName.Replace("..", ".#"));
+ if (mr == null)
+ mr = XmlDocKeyProvider.FindMemberByKey(foundAssembly.AssemblyDefinition.MainModule, "P:" + fullMethodName.Replace("..", ".#"));
+ return mr;
+ }
+
+ static void OnCurrentAssemblyListChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action != NotifyCollectionChangedAction.Reset
+ || activeAssemblyListName == MainWindow.Instance.CurrentAssemblyList.ListName)
+ return;
+ if (activeAssemblyListName != null)
+ SaveBookmarks();
+ BookmarkManager.Clear();
+ activeAssemblyListName = MainWindow.Instance.CurrentAssemblyList.ListName;
+ LoadBookmarks();
+ }
+
+ static void SaveBookmarks()
+ {
+ ILSpySettings.Update(
+ delegate (XElement root) {
+ XElement doc = root.Element("Bookmarks");
+ if (doc == null)
+ {
+ doc = new XElement("Bookmarks");
+ root.Add(doc);
+ }
+ XElement listElement = doc.Elements("List").FirstOrDefault(e => (string)e.Attribute("name") == activeAssemblyListName);
+ if (listElement != null)
+ listElement.ReplaceWith(SaveActiveBookmarks());
+ else
+ doc.Add(SaveActiveBookmarks());
+ });
+ }
+
+ static XElement SaveActiveBookmarks()
+ {
+ XElement list = BookmarkManager.SaveBookmarks();
+ list.SetAttributeValue("name", activeAssemblyListName);
+ return list;
+ }
+
+ static void LoadBookmarks()
+ {
+ ILSpySettings settings = ILSpySettings.Load();
+ XElement doc = settings["Bookmarks"];
+ if (doc == null)
+ {
+ return;
+ }
+ XElement listElement = doc.Elements("List").FirstOrDefault(e => (string)e.Attribute("name") == activeAssemblyListName);
+ if (listElement == null)
+ return;
+ BookmarkManager.LoadBookmarks(listElement);
+ }
+ }
+}
@@ -91,7 +91,6 @@ protected virtual void OnProcessSelected(ProcessEventArgs e)
public WindowsDebugger()
{
-
}
#region IDebugger Members
@@ -16,6 +16,7 @@
using ICSharpCode.ILSpy.Bookmarks;
using ICSharpCode.ILSpy.Debugger.Bookmarks;
using ICSharpCode.ILSpy.Options;
+using ICSharpCode.ILSpy.Debugger.Services;
namespace ICSharpCode.ILSpy.Debugger.UI
{
@@ -102,6 +103,12 @@ void view_KeyUp(object sender, KeyEventArgs e)
[ExportMainMenuCommand(Menu="_Debugger", Header="Show _Breakpoints", MenuCategory="View", MenuOrder=8)]
public class BookmarkManagerPanelCommand : SimpleCommand
{
+ public BookmarkManagerPanelCommand()
+ {
+ // (mis)use the fact that loaded on startup
+ BreakpointService.Initialize();
+ }
+
public override void Execute(object parameter)
{
BreakpointPanel.Instance.Show();
@@ -229,11 +229,8 @@ void view_MouseDoubleClick(object sender, MouseButtonEventArgs e)
if (null == selectedItem)
return;
- var foundAssembly = MainWindow.Instance.CurrentAssemblyList.OpenAssembly(selectedItem.Frame.MethodInfo.DebugModule.FullPath);
- if (null == foundAssembly || null == foundAssembly.AssemblyDefinition)
- return;
-
- MemberReference mr = XmlDocKeyProvider.FindMemberByKey(foundAssembly.AssemblyDefinition.MainModule, "M:" + selectedItem.Name);
+ MemberReference mr = BreakpointService.ResolveMethod(selectedItem.Frame.MethodInfo.DebugModule.FullPath,
+ selectedItem.Name);
if (mr == null)
return;
MainWindow.Instance.JumpToReference(mr);
@@ -29,6 +29,7 @@
using Mono.Cecil.Cil;
using Mono.CSharp;
using Cecil = Mono.Cecil;
+using System.Globalization;
namespace ICSharpCode.Decompiler.ILAst
{
@@ -230,7 +231,21 @@ public override string ToString()
{
return string.Format("{0}-{1}", From.ToString("X"), To.ToString("X"));
}
-
+
+ public static bool TryParse(string value, out ILRange result)
+ {
+ result = null;
+ string[] p = value.Split('-');
+ if (p == null || p.Length != 2)
+ return false;
+ ILRange ilr = new ILRange();
+ if (!int.TryParse(p[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ilr.From)
+ || !int.TryParse(p[1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ilr.To))
+ return false;
+ result = ilr;
+ return true;
+ }
+
public static List<ILRange> OrderAndJoint(IEnumerable<ILRange> input)
{
if (input == null)
@@ -7,9 +7,38 @@
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
using Mono.CSharp;
+using System.ComponentModel.Composition;
+using System.Xml.Linq;
+using System.Linq;
namespace ICSharpCode.ILSpy.Bookmarks
{
+ /// <summary>
+ /// Bookmark specializations may provide an exported implementation of this interface to support save and load for these bookmarks.
+ /// </summary>
+ public interface IBookmarkPersistence
+ {
+ XElement Save(BookmarkBase bookmark);
+ BookmarkBase Load(XElement bookmarkNode);
+ }
+
+ public interface IBookmarkPersistenceMetadata
+ {
+ Type SupportedType { get; }
+ }
+
+ [MetadataAttribute]
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class ExportBookmarkPersistenceAttribute : ExportAttribute, IBookmarkPersistenceMetadata
+ {
+ public ExportBookmarkPersistenceAttribute()
+ : base(typeof(IBookmarkPersistence))
+ {
+ }
+
+ public Type SupportedType { get; set; }
+ }
+
/// <summary>
/// Static class that maintains the list of bookmarks and breakpoints.
/// </summary>
@@ -112,5 +141,38 @@ static void OnAdded(BookmarkEventArgs e)
public static event BookmarkEventHandler Removed;
public static event BookmarkEventHandler Added;
- }
+
+ #region persistence
+ [ImportMany(typeof(IBookmarkPersistence))]
+ public static IEnumerable<Lazy<IBookmarkPersistence, IBookmarkPersistenceMetadata>> PersistenceEntries { get; set; }
+
+ public static XElement SaveBookmarks()
+ {
+ XElement list = new XElement("List");
+ foreach (var b in BookmarkManager.Bookmarks)
+ {
+ var persistenceHandler = PersistenceEntries.FirstOrDefault(e => e.Metadata.SupportedType == b.GetType());
+ if (null == persistenceHandler)
+ continue;
+ var bookmarkNode = persistenceHandler.Value.Save(b);
+ bookmarkNode.SetAttributeValue("bookmarkType", b.GetType().Name);
+ list.Add(bookmarkNode);
+ }
+ return list;
+ }
+
+ public static void LoadBookmarks(XElement bookmarkList)
+ {
+ foreach (var bookmarkNode in bookmarkList.Elements("Bookmark"))
+ {
+ var persistenceHandler =
+ PersistenceEntries.FirstOrDefault(e => e.Metadata.SupportedType.Name == (string)bookmarkNode.Attribute("bookmarkType"));
+ if (null == persistenceHandler)
+ continue;
+ BookmarkBase newMark = persistenceHandler.Value.Load(bookmarkNode);
+ AddMark(newMark);
+ }
+ }
+ #endregion
+ }
}
@@ -44,6 +44,7 @@
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
+ <Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
@@ -82,12 +83,7 @@
<Compile Include="Services\IDebugger.cs" />
<Compile Include="Services\ParserService.cs" />
</ItemGroup>
- <ItemGroup>
- <Folder Include="AvalonEdit" />
- <Folder Include="Bookmarks" />
- <Folder Include="Models" />
- <Folder Include="Services" />
- </ItemGroup>
+ <ItemGroup />
<ItemGroup>
<ProjectReference Include="..\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
Oops, something went wrong.

0 comments on commit 6b72153

Please sign in to comment.