mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
12 KiB
364 lines
12 KiB
// 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) |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Text; |
|
|
|
using ICSharpCode.NRefactory; |
|
using ILSpy.Debugger.Bookmarks; |
|
|
|
namespace ILSpy.Debugger.Services |
|
{ |
|
public static class DebuggerService |
|
{ |
|
static IDebugger currentDebugger; |
|
|
|
static DebuggerService() |
|
{ |
|
BookmarkManager.Added += BookmarkAdded; |
|
BookmarkManager.Removed += BookmarkRemoved; |
|
} |
|
|
|
static IDebugger GetCompatibleDebugger() |
|
{ |
|
return new WindowsDebugger(); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the current debugger. The debugger addin is loaded on demand; so if you |
|
/// just want to check a property like IsDebugging, check <see cref="IsDebuggerLoaded"/> |
|
/// before using this property. |
|
/// </summary> |
|
public static IDebugger CurrentDebugger { |
|
get { |
|
if (currentDebugger == null) { |
|
currentDebugger = GetCompatibleDebugger(); |
|
currentDebugger.DebugStarting += new EventHandler(OnDebugStarting); |
|
currentDebugger.DebugStarted += new EventHandler(OnDebugStarted); |
|
currentDebugger.DebugStopped += new EventHandler(OnDebugStopped); |
|
} |
|
return currentDebugger; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Returns true if debugger is already loaded. |
|
/// </summary> |
|
public static bool IsDebuggerLoaded { |
|
get { |
|
return currentDebugger != null; |
|
} |
|
} |
|
|
|
static bool debuggerStarted; |
|
|
|
/// <summary> |
|
/// Gets whether the debugger is currently active. |
|
/// </summary> |
|
public static bool IsDebuggerStarted { |
|
get { return debuggerStarted; } |
|
} |
|
|
|
public static event EventHandler DebugStarting; |
|
public static event EventHandler DebugStarted; |
|
public static event EventHandler DebugStopped; |
|
|
|
static void OnDebugStarting(object sender, EventArgs e) |
|
{ |
|
ClearDebugMessages(); |
|
|
|
if (DebugStarting != null) |
|
DebugStarting(null, e); |
|
} |
|
|
|
static void OnDebugStarted(object sender, EventArgs e) |
|
{ |
|
debuggerStarted = true; |
|
if (DebugStarted != null) |
|
DebugStarted(null, e); |
|
} |
|
|
|
static void OnDebugStopped(object sender, EventArgs e) |
|
{ |
|
debuggerStarted = false; |
|
|
|
RemoveCurrentLineMarker(); |
|
|
|
if (DebugStopped != null) |
|
DebugStopped(null, e); |
|
} |
|
|
|
public static void ClearDebugMessages() |
|
{ |
|
|
|
} |
|
|
|
public static void PrintDebugMessage(string msg) |
|
{ |
|
|
|
} |
|
|
|
public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointChanged; |
|
public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointAdded; |
|
public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointRemoved; |
|
|
|
static void OnBreakPointChanged(BreakpointBookmarkEventArgs e) |
|
{ |
|
if (BreakPointChanged != null) { |
|
BreakPointChanged(null, e); |
|
} |
|
} |
|
|
|
static void OnBreakPointAdded(BreakpointBookmarkEventArgs e) |
|
{ |
|
if (BreakPointAdded != null) { |
|
BreakPointAdded(null, e); |
|
} |
|
} |
|
|
|
static void OnBreakPointRemoved(BreakpointBookmarkEventArgs e) |
|
{ |
|
if (BreakPointRemoved != null) { |
|
BreakPointRemoved(null, e); |
|
} |
|
} |
|
|
|
public static IList<BreakpointBookmark> Breakpoints { |
|
get { |
|
List<BreakpointBookmark> breakpoints = new List<BreakpointBookmark>(); |
|
foreach (var bookmark in BookmarkManager.Bookmarks) { |
|
BreakpointBookmark breakpoint = bookmark as BreakpointBookmark; |
|
if (breakpoint != null) { |
|
breakpoints.Add(breakpoint); |
|
} |
|
} |
|
return breakpoints.AsReadOnly(); |
|
} |
|
} |
|
|
|
static void BookmarkAdded(object sender, BookmarkEventArgs e) |
|
{ |
|
BreakpointBookmark bb = e.Bookmark as BreakpointBookmark; |
|
if (bb != null) { |
|
OnBreakPointAdded(new BreakpointBookmarkEventArgs(bb)); |
|
} |
|
} |
|
|
|
static void BookmarkRemoved(object sender, BookmarkEventArgs e) |
|
{ |
|
BreakpointBookmark bb = e.Bookmark as BreakpointBookmark; |
|
if (bb != null) { |
|
OnBreakPointRemoved(new BreakpointBookmarkEventArgs(bb)); |
|
} |
|
} |
|
|
|
static void BookmarkChanged(object sender, EventArgs e) |
|
{ |
|
BreakpointBookmark bb = sender as BreakpointBookmark; |
|
if (bb != null) { |
|
OnBreakPointChanged(new BreakpointBookmarkEventArgs(bb)); |
|
} |
|
} |
|
|
|
public static void ToggleBreakpointAt(string typeName, int lineNumber) |
|
{ |
|
BookmarkManager.ToggleBookmark( |
|
typeName, lineNumber, |
|
b => b.CanToggle && b is BreakpointBookmark, |
|
location => new BreakpointBookmark(typeName, location, BreakpointAction.Break)); |
|
} |
|
|
|
/* TODO: reimplement this stuff |
|
static void ViewContentOpened(object sender, ViewContentEventArgs e) |
|
{ |
|
textArea.IconBarMargin.MouseDown += IconBarMouseDown; |
|
textArea.ToolTipRequest += TextAreaToolTipRequest; |
|
textArea.MouseLeave += TextAreaMouseLeave; |
|
}*/ |
|
|
|
public static void RemoveCurrentLineMarker() |
|
{ |
|
CurrentLineBookmark.Remove(); |
|
} |
|
|
|
public static void JumpToCurrentLine(string SourceFullFilename, int StartLine, int StartColumn, int EndLine, int EndColumn) |
|
{ |
|
// IViewContent viewContent = FileService.OpenFile(SourceFullFilename); |
|
// if (viewContent is ITextEditorProvider) |
|
// ((ITextEditorProvider)viewContent).TextEditor.JumpTo(StartLine, StartColumn); |
|
// CurrentLineBookmark.SetPosition(viewContent, StartLine, StartColumn, EndLine, EndColumn); |
|
} |
|
|
|
#region Tool tips |
|
/// <summary> |
|
/// Gets debugger tooltip information for the specified position. |
|
/// A descriptive string for the element or a DebuggerTooltipControl |
|
/// showing its current value (when in debugging mode) can be returned |
|
/// through the ToolTipRequestEventArgs.SetTooltip() method. |
|
/// </summary> |
|
// internal static void HandleToolTipRequest(ToolTipRequestEventArgs e) |
|
// { |
|
// if (!e.InDocument) |
|
// return; |
|
// Location logicPos = e.LogicalPosition; |
|
// var doc = e.Editor.Document; |
|
// IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(e.Editor.FileName); |
|
// if (expressionFinder == null) |
|
// return; |
|
// var currentLine = doc.GetLine(logicPos.Y); |
|
// if (logicPos.X > currentLine.Length) |
|
// return; |
|
// string textContent = doc.Text; |
|
// ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, doc.PositionToOffset(logicPos.Line, logicPos.Column)); |
|
// string expression = (expressionResult.Expression ?? "").Trim(); |
|
// if (expression.Length > 0) { |
|
// // Look if it is variable |
|
// ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y, logicPos.X, e.Editor.FileName, textContent); |
|
// bool debuggerCanShowValue; |
|
// string toolTipText = GetText(result, expression, out debuggerCanShowValue); |
|
// if (Control.ModifierKeys == Keys.Control) { |
|
// toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText; |
|
// debuggerCanShowValue = false; |
|
// } |
|
// if (toolTipText != null) { |
|
// if (debuggerCanShowValue && currentDebugger != null) { |
|
// object toolTip = currentDebugger.GetTooltipControl(e.LogicalPosition, expressionResult.Expression); |
|
// if (toolTip != null) |
|
// e.SetToolTip(toolTip); |
|
// else |
|
// e.SetToolTip(toolTipText); |
|
// } else { |
|
// e.SetToolTip(toolTipText); |
|
// } |
|
// } |
|
// } else { |
|
// #if DEBUG |
|
// if (Control.ModifierKeys == Keys.Control) { |
|
// e.SetToolTip("no expr: " + expressionResult.ToString()); |
|
// } |
|
// #endif |
|
// } |
|
// } |
|
// |
|
// static string GetText(ResolveResult result, string expression, out bool debuggerCanShowValue) |
|
// { |
|
// debuggerCanShowValue = false; |
|
// if (result == null) { |
|
// // when pressing control, show the expression even when it could not be resolved |
|
// return (Control.ModifierKeys == Keys.Control) ? "" : null; |
|
// } |
|
// if (result is MixedResolveResult) |
|
// return GetText(((MixedResolveResult)result).PrimaryResult, expression, out debuggerCanShowValue); |
|
// else if (result is DelegateCallResolveResult) |
|
// return GetText(((DelegateCallResolveResult)result).Target, expression, out debuggerCanShowValue); |
|
// |
|
// IAmbience ambience = AmbienceService.GetCurrentAmbience(); |
|
// ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.UseFullyQualifiedMemberNames; |
|
// if (result is MemberResolveResult) { |
|
// return GetMemberText(ambience, ((MemberResolveResult)result).ResolvedMember, expression, out debuggerCanShowValue); |
|
// } else if (result is LocalResolveResult) { |
|
// LocalResolveResult rr = (LocalResolveResult)result; |
|
// ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedTypeNames |
|
// | ConversionFlags.ShowReturnType | ConversionFlags.ShowDefinitionKeyWord; |
|
// StringBuilder b = new StringBuilder(); |
|
// if (rr.IsParameter) |
|
// b.Append("parameter "); |
|
// else |
|
// b.Append("local variable "); |
|
// b.Append(ambience.Convert(rr.Field)); |
|
// if (currentDebugger != null) { |
|
// string currentValue = currentDebugger.GetValueAsString(rr.VariableName); |
|
// if (currentValue != null) { |
|
// debuggerCanShowValue = true; |
|
// b.Append(" = "); |
|
// if (currentValue.Length > 256) |
|
// currentValue = currentValue.Substring(0, 256) + "..."; |
|
// b.Append(currentValue); |
|
// } |
|
// } |
|
// return b.ToString(); |
|
// } else if (result is NamespaceResolveResult) { |
|
// return "namespace " + ((NamespaceResolveResult)result).Name; |
|
// } else if (result is TypeResolveResult) { |
|
// IClass c = ((TypeResolveResult)result).ResolvedClass; |
|
// if (c != null) |
|
// return GetMemberText(ambience, c, expression, out debuggerCanShowValue); |
|
// else |
|
// return ambience.Convert(result.ResolvedType); |
|
// } else if (result is MethodGroupResolveResult) { |
|
// MethodGroupResolveResult mrr = result as MethodGroupResolveResult; |
|
// IMethod m = mrr.GetMethodIfSingleOverload(); |
|
// IMethod m2 = mrr.GetMethodWithEmptyParameterList(); |
|
// if (m != null) |
|
// return GetMemberText(ambience, m, expression, out debuggerCanShowValue); |
|
// else if (ambience is VBNetAmbience && m2 != null) |
|
// return GetMemberText(ambience, m2, expression, out debuggerCanShowValue); |
|
// else |
|
// return "Overload of " + ambience.Convert(mrr.ContainingType) + "." + mrr.Name; |
|
// } else { |
|
// if (Control.ModifierKeys == Keys.Control) { |
|
// if (result.ResolvedType != null) |
|
// return "expression of type " + ambience.Convert(result.ResolvedType); |
|
// else |
|
// return "ResolveResult without ResolvedType"; |
|
// } else { |
|
// return null; |
|
// } |
|
// } |
|
// } |
|
// |
|
// static string GetMemberText(IAmbience ambience, IEntity member, string expression, out bool debuggerCanShowValue) |
|
// { |
|
// bool tryDisplayValue = false; |
|
// debuggerCanShowValue = false; |
|
// StringBuilder text = new StringBuilder(); |
|
// if (member is IField) { |
|
// text.Append(ambience.Convert(member as IField)); |
|
// tryDisplayValue = true; |
|
// } else if (member is IProperty) { |
|
// text.Append(ambience.Convert(member as IProperty)); |
|
// tryDisplayValue = true; |
|
// } else if (member is IEvent) { |
|
// text.Append(ambience.Convert(member as IEvent)); |
|
// } else if (member is IMethod) { |
|
// text.Append(ambience.Convert(member as IMethod)); |
|
// } else if (member is IClass) { |
|
// text.Append(ambience.Convert(member as IClass)); |
|
// } else { |
|
// text.Append("unknown member "); |
|
// text.Append(member.ToString()); |
|
// } |
|
// if (tryDisplayValue && currentDebugger != null) { |
|
// LoggingService.Info("asking debugger for value of '" + expression + "'"); |
|
// string currentValue = currentDebugger.GetValueAsString(expression); |
|
// if (currentValue != null) { |
|
// debuggerCanShowValue = true; |
|
// text.Append(" = "); |
|
// text.Append(currentValue); |
|
// } |
|
// } |
|
// string documentation = member.Documentation; |
|
// if (documentation != null && documentation.Length > 0) { |
|
// text.Append('\n'); |
|
// text.Append(ICSharpCode.SharpDevelop.Editor.CodeCompletion.CodeCompletionItem.ConvertDocumentation(documentation)); |
|
// } |
|
// return text.ToString(); |
|
// } |
|
#endregion |
|
} |
|
|
|
/// <summary> |
|
/// Provides the default debugger tooltips on the text area. |
|
/// </summary> |
|
/// <remarks> |
|
/// This class must be public because it is accessed via the AddInTree. |
|
/// </remarks> |
|
// public class DebuggerTextAreaToolTipProvider : ITextAreaToolTipProvider |
|
// { |
|
// public void HandleToolTipRequest(ToolTipRequestEventArgs e) |
|
// { |
|
// DebuggerService.HandleToolTipRequest(e); |
|
// } |
|
// } |
|
}
|
|
|