From b46136786e70712de76a4924658ef01133c4a2c8 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Wed, 16 Feb 2011 16:50:29 +0200 Subject: [PATCH] Show tooltip when debugging. --- .../AvalonEdit/IconBarMargin.cs | 22 ++- .../Bookmarks/BookmarkManager.cs | 1 + .../Bookmarks/BreakpointBookmark.cs | 3 +- .../Bookmarks/CurrentLineBookmark.cs | 2 +- Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj | 1 + .../Services/Debugger/DebuggerService.cs | 9 +- .../Services/Debugger/IDebugger.cs | 16 ++ .../Services/Debugger/WindowsDebugger.cs | 167 ++++++++++-------- .../ToolTips/DebuggerTooltipControl.xaml.cs | 6 +- .../ToolTips/TextEditorListener.cs | 5 +- .../UI/AttachToProcessWindow.xaml.cs | 9 +- ILSpy/MainWindow.xaml | 4 +- ILSpy/MainWindow.xaml.cs | 53 +++--- ILSpy/TextView/DecompilerTextView.cs | 10 +- 14 files changed, 181 insertions(+), 127 deletions(-) diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs index 77ff1c8c6..ba0419317 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs @@ -40,6 +40,12 @@ namespace ILSpy.Debugger.AvalonEdit set { currentTypeName = value; } } + public IconBarMargin() + { + BookmarkManager.Added += delegate { InvalidateVisual(); }; + BookmarkManager.Removed += delegate { InvalidateVisual(); }; + } + public virtual void Dispose() { this.TextView = null; // detach from TextView (will also detach from manager) @@ -200,6 +206,13 @@ namespace ILSpy.Debugger.AvalonEdit dragStarted = true; InvalidateVisual(); } + + BreakpointBookmark bm = BookmarkManager.Bookmarks.Find( + b => b.TypeName == CurrentType.FullName && + b.LineNumber == GetLineFromMousePosition(e) + && b is BreakpointBookmark) as BreakpointBookmark; + + this.ToolTip = (bm != null) ? bm.Tooltip : null; } protected override void OnMouseUp(MouseButtonEventArgs e) @@ -215,11 +228,11 @@ namespace ILSpy.Debugger.AvalonEdit CancelDragDrop(); } if (!e.Handled && line != 0) { - IBookmark bm = GetBookmarkFromLine(line); + BookmarkBase bm = GetBookmarkFromLine(line); if (bm != null) { bm.MouseUp(e); if (CurrentType != null) { - DebuggerService.ToggleBreakpointAt(CurrentType.FullName, line); + BookmarkManager.RemoveMark(bm); } InvalidateVisual(); if (e.Handled) @@ -228,7 +241,10 @@ namespace ILSpy.Debugger.AvalonEdit if (e.ChangedButton == MouseButton.Left) { if (CurrentType != null) { // no bookmark on the line: create a new breakpoint - DebuggerService.ToggleBreakpointAt(CurrentType.FullName, line); + DebuggerService.ToggleBreakpointAt( + CurrentType.FullName, + line, + DebuggerService.CurrentDebugger.Language); } } InvalidateVisual(); diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs index 747edfa11..a92762c40 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs @@ -118,6 +118,7 @@ namespace ILSpy.Debugger.Bookmarks return; } } + // no bookmark at that line: create a new bookmark BookmarkManager.AddMark(bookmarkFactory(new AstLocation(line, 0))); } diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs index ba72ead6f..ff9da6b5b 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs @@ -83,9 +83,10 @@ namespace ILSpy.Debugger.Bookmarks set { tooltip = value; } } - public BreakpointBookmark(string typeName, AstLocation location, BreakpointAction action) : base(typeName, location) + public BreakpointBookmark(string typeName, AstLocation location, BreakpointAction action, DecompiledLanguages language) : base(typeName, location) { this.action = action; + this.tooltip = language.ToString(); } public override ImageSource Image { diff --git a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs index e043b578e..d54b2d675 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs @@ -27,7 +27,7 @@ namespace ILSpy.Debugger.Bookmarks endLine = makerEndLine; endColumn = makerEndColumn; - instance = new CurrentLineBookmark(typeName, new AstLocation(startColumn, startLine)); + instance = new CurrentLineBookmark(typeName, new AstLocation(startLine, startColumn)); BookmarkManager.AddMark(instance); } diff --git a/Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj b/Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj index 4e92be823..4812f6813 100644 --- a/Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj +++ b/Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj @@ -114,6 +114,7 @@ + diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs b/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs index 6daba5192..b94f163fb 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs @@ -27,7 +27,7 @@ namespace ILSpy.Debugger.Services static IDebugger GetCompatibleDebugger() { - return new WindowsDebugger(); + return currentDebugger = new WindowsDebugger(); } /// @@ -166,12 +166,12 @@ namespace ILSpy.Debugger.Services } } - public static void ToggleBreakpointAt(string typeName, int lineNumber) + public static void ToggleBreakpointAt(string typeName, int lineNumber, DecompiledLanguages language) { BookmarkManager.ToggleBookmark( typeName, lineNumber, b => b.CanToggle && b is BreakpointBookmark, - location => new BreakpointBookmark(typeName, location, BreakpointAction.Break)); + location => new BreakpointBookmark(typeName, location, BreakpointAction.Break, language)); } /* TODO: reimplement this stuff @@ -209,9 +209,8 @@ namespace ILSpy.Debugger.Services string variable = ParserService.SimpleParseAt(doc.Text, doc.GetOffset(new TextLocation(logicPos.Line, logicPos.Column))); - - if (currentDebugger == null || !currentDebugger.IsDebugging) { + if (currentDebugger == null || !currentDebugger.IsDebugging || !currentDebugger.CanEvaluate) { e.ContentToShow = variable; } else { diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs index 0a408c032..abef371dc 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs @@ -9,8 +9,24 @@ using Mono.CSharp; namespace ILSpy.Debugger.Services { + public enum DecompiledLanguages + { + IL, + CSharp + } + public interface IDebugger : IDisposable { + /// + /// Gets or sets the decompiled language. + /// + DecompiledLanguages Language { get; set; } + + /// + /// Gets whether the debugger can evaluate the expression. + /// + bool CanEvaluate { get; } + /// /// Returns true if debuger is attached to a process /// diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs index 8ce2fa1bb..31816c1cb 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs @@ -99,6 +99,8 @@ namespace ILSpy.Debugger.Services string errorProcessPaused = "Error.ProcessPaused"; string errorCannotStepNoActiveFunction = "Threads.CannotStepNoActiveFunction"; + public DecompiledLanguages Language { get; set; } + public bool IsDebugging { get { return ServiceInitialized && debuggedProcess != null; @@ -372,7 +374,8 @@ namespace ILSpy.Debugger.Services } } - bool CanEvaluate + /// + public bool CanEvaluate { get { return debuggedProcess != null && !debuggedProcess.IsRunning && debuggedProcess.SelectedStackFrame != null; @@ -385,7 +388,7 @@ namespace ILSpy.Debugger.Services /// public object GetTooltipControl(AstLocation logicalPosition, string variableName) { - return new DebuggerTooltipControl(logicalPosition, new ExpressionNode(ImageService.Breakpoint, variableName, null)); + return new DebuggerTooltipControl(logicalPosition, new ExpressionNode(null, variableName, null)); //FIXME // try { // var tooltipExpression = GetExpression(variableName); @@ -489,13 +492,29 @@ namespace ILSpy.Debugger.Services void AddBreakpoint(BreakpointBookmark bookmark) { - uint token; - ILCodeMapping map = ILCodeMappings.GetInstructionByTypeAndLine(bookmark.TypeName, bookmark.LineNumber, out token); + Breakpoint breakpoint = null; + + switch (Language) { + case DecompiledLanguages.IL: + uint token; + ILCodeMapping map = ILCodeMappings.GetInstructionByTypeAndLine(bookmark.TypeName, bookmark.LineNumber, out token); + + if (map != null) { + breakpoint = new ILBreakpoint(debugger, bookmark.LineNumber, token, map.ILInstruction.Offset , bookmark.IsEnabled); + debugger.Breakpoints.Add(breakpoint); + } + break; + + case DecompiledLanguages.CSharp: + break; + + default: + throw new NotImplementedException("Not implemented!"); + } + + if (breakpoint == null) + return; - if (map != null) { - Breakpoint breakpoint = new ILBreakpoint(debugger, bookmark.LineNumber, token, map.ILInstruction.Offset , bookmark.IsEnabled); - debugger.Breakpoints.Add(breakpoint); - // Action setBookmarkColor = delegate { // if (debugger.Processes.Count == 0) { // bookmark.IsHealthy = true; @@ -524,65 +543,64 @@ namespace ILSpy.Debugger.Services // } // } // }; - - // event handlers on bookmark and breakpoint don't need deregistration - bookmark.IsEnabledChanged += delegate { - breakpoint.Enabled = bookmark.IsEnabled; - }; - breakpoint.Set += delegate { - //setBookmarkColor(); - }; - + + // event handlers on bookmark and breakpoint don't need deregistration + bookmark.IsEnabledChanged += delegate { + breakpoint.Enabled = bookmark.IsEnabled; + }; + breakpoint.Set += delegate { //setBookmarkColor(); - - EventHandler> bp_debugger_ProcessStarted = (sender, e) => { - //setBookmarkColor(); - // User can change line number by inserting or deleting lines - breakpoint.Line = bookmark.LineNumber; - }; - EventHandler> bp_debugger_ProcessExited = (sender, e) => { - //setBookmarkColor(); - }; - - EventHandler bp_debugger_BreakpointHit = - new EventHandler( - delegate(object sender, BreakpointEventArgs e) - { - //LoggingService.Debug(bookmark.Action + " " + bookmark.ScriptLanguage + " " + bookmark.Condition); - - switch (bookmark.Action) { - case BreakpointAction.Break: - break; - case BreakpointAction.Condition: + }; + + //setBookmarkColor(); + + EventHandler> bp_debugger_ProcessStarted = (sender, e) => { + //setBookmarkColor(); + // User can change line number by inserting or deleting lines + breakpoint.Line = bookmark.LineNumber; + }; + EventHandler> bp_debugger_ProcessExited = (sender, e) => { + //setBookmarkColor(); + }; + + EventHandler bp_debugger_BreakpointHit = + new EventHandler( + delegate(object sender, BreakpointEventArgs e) + { + //LoggingService.Debug(bookmark.Action + " " + bookmark.ScriptLanguage + " " + bookmark.Condition); + + switch (bookmark.Action) { + case BreakpointAction.Break: + break; + case BreakpointAction.Condition: // if (Evaluate(bookmark.Condition, bookmark.ScriptLanguage)) // DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAtBecause}") + "\n", bookmark.LineNumber, bookmark.FileName, bookmark.Condition)); // else // this.debuggedProcess.AsyncContinue(); - break; - case BreakpointAction.Trace: - //DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAt}") + "\n", bookmark.LineNumber, bookmark.FileName)); - break; - } - }); - - BookmarkEventHandler bp_bookmarkManager_Removed = null; - bp_bookmarkManager_Removed = (sender, e) => { - if (bookmark == e.Bookmark) { - debugger.Breakpoints.Remove(breakpoint); - - // unregister the events - debugger.Processes.Added -= bp_debugger_ProcessStarted; - debugger.Processes.Removed -= bp_debugger_ProcessExited; - breakpoint.Hit -= bp_debugger_BreakpointHit; - BookmarkManager.Removed -= bp_bookmarkManager_Removed; - } - }; - // register the events - debugger.Processes.Added += bp_debugger_ProcessStarted; - debugger.Processes.Removed += bp_debugger_ProcessExited; - breakpoint.Hit += bp_debugger_BreakpointHit; - BookmarkManager.Removed += bp_bookmarkManager_Removed; - } + break; + case BreakpointAction.Trace: + //DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAt}") + "\n", bookmark.LineNumber, bookmark.FileName)); + break; + } + }); + + BookmarkEventHandler bp_bookmarkManager_Removed = null; + bp_bookmarkManager_Removed = (sender, e) => { + if (bookmark == e.Bookmark) { + debugger.Breakpoints.Remove(breakpoint); + + // unregister the events + debugger.Processes.Added -= bp_debugger_ProcessStarted; + debugger.Processes.Removed -= bp_debugger_ProcessExited; + breakpoint.Hit -= bp_debugger_BreakpointHit; + BookmarkManager.Removed -= bp_bookmarkManager_Removed; + } + }; + // register the events + debugger.Processes.Added += bp_debugger_ProcessStarted; + debugger.Processes.Removed += bp_debugger_ProcessExited; + breakpoint.Hit += bp_debugger_BreakpointHit; + BookmarkManager.Removed += bp_bookmarkManager_Removed; } bool Evaluate(string code, string language) @@ -723,13 +741,24 @@ namespace ILSpy.Debugger.Services DebuggerService.RemoveCurrentLineMarker(); if (debuggedProcess != null && debuggedProcess.SelectedStackFrame != null) { - uint token = (uint)debuggedProcess.SelectedStackFrame.MethodInfo.MetadataToken; - int ilOffset = debuggedProcess.SelectedStackFrame.IP; - int line; - string typeName; - ILCodeMappings.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line); - if (typeName != null) { - DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); + switch (Language) { + case DecompiledLanguages.IL: + // IL mapping + uint token = (uint)debuggedProcess.SelectedStackFrame.MethodInfo.MetadataToken; + int ilOffset = debuggedProcess.SelectedStackFrame.IP; + int line; + string typeName; + ILCodeMappings.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line); + if (typeName != null) + DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); + break; + + case DecompiledLanguages.CSharp: + // FIXME CSharp mappings + break; + + default: + throw new NotImplementedException("The language is not supported!"); } } } diff --git a/Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs b/Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs index 6064f728e..656bacbc1 100644 --- a/Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs +++ b/Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs @@ -30,7 +30,7 @@ namespace ILSpy.Debugger.Tooltips private const int InitialItemsCount = 12; private const int VisibleItemsCount = 11; - private bool showPins = true; + private bool showPins; private LazyItemsControl lazyGrid; private IEnumerable itemsSource; readonly AstLocation logicalPosition; @@ -55,7 +55,7 @@ namespace ILSpy.Debugger.Tooltips this.itemsSource = nodes; } - public DebuggerTooltipControl(DebuggerTooltipControl parentControl, AstLocation logicalPosition, bool showPins = true) + public DebuggerTooltipControl(DebuggerTooltipControl parentControl, AstLocation logicalPosition, bool showPins = false) : this(logicalPosition) { this.parentControl = parentControl; @@ -65,7 +65,7 @@ namespace ILSpy.Debugger.Tooltips private void OnLoaded(object sender, RoutedEventArgs e) { if (!showPins) { - dataGrid.Columns[5].Visibility = Visibility.Collapsed; + dataGrid.Columns[4].Visibility = Visibility.Collapsed; } SetItemsSource(this.itemsSource); diff --git a/Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs b/Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs index b76c336c1..fd6aa4bd0 100644 --- a/Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs +++ b/Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs @@ -67,10 +67,7 @@ namespace ILSpy.Debugger.ToolTips } void OnMouseHoverStopped(MouseEventArgs e) - { - if (popup != null) - popup.IsOpen = false; - + { if (toolTip != null) toolTip.IsOpen = false; } diff --git a/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs b/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs index d9fe9e4a2..352bc023c 100644 --- a/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs +++ b/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs @@ -34,13 +34,6 @@ namespace ILSpy.Debugger.UI /// public partial class AttachToProcessWindow : Window { - public static IDebugger Debugger { get; private set; } - - static AttachToProcessWindow() - { - Debugger = new WindowsDebugger(); - } - public AttachToProcessWindow() { InitializeComponent(); @@ -92,7 +85,7 @@ namespace ILSpy.Debugger.UI // start attaching var process = ((RunningProcess)this.RunningProcesses.SelectedItem).Process; - Debugger.Attach(process); + DebuggerService.CurrentDebugger.Attach(process); this.DialogResult = true; } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index c9423e9aa..f0af892f7 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -156,7 +156,9 @@ + SelectedItem="{Binding FilterSettings.Language}" + SelectionChanged="LanguageComboBox_SelectionChanged" + />