#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
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.
 
 
 
 
 
 

618 lines
20 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krger" email="mike@icsharpcode.net"/>
// <version value="$version"/>
// </file>
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor;
using System.Drawing;
using System.Windows.Forms;
namespace ICSharpCode.Core
{
public static class DebuggerService
{
static System.Diagnostics.Process standardProcess = null;
static bool isRunning = false;
static IDebugger defaultDebugger = null;
static IDebugger currentDebugger = null;
static ArrayList debugger = null;
//static ArrayList breakpoints = new ArrayList();
/*public static ArrayList Breakpoints {
get {
return breakpoints;
}
}*/
public static IDebugger CurrentDebugger {
get {
if (currentDebugger != null) {
return currentDebugger;
}
if (debugger == null) {
InitializeService();
}
if (debugger != null) {
IProject project = null;
if (ProjectService.OpenSolution != null) {
project = ProjectService.OpenSolution.StartupProject;
}
foreach (IDebugger d in debugger) {
if (d.CanDebug(project)) {
currentDebugger = d;
return d;
}
}
}
if (defaultDebugger == null) {
defaultDebugger = new DefaultDebugger();
}
currentDebugger = defaultDebugger;
return defaultDebugger;
}
}
public static bool IsProcessRuning {
get {
if (standardProcess != null) {
return isRunning;
}
if (currentDebugger != null) {
return currentDebugger.IsProcessRunning;
}
return false;
}
}
public static bool IsDebugging {
get {
if (currentDebugger == null) {
return false;
}
return currentDebugger.IsDebugging;
}
}
static DebuggerService()
{
InitializeService();
InitializeService2();
}
static MessageViewCategory debugCategory = null;
static void EnsureDebugCategory()
{
if (debugCategory == null) {
debugCategory = new MessageViewCategory("Debug", "${res:MainWindow.Windows.OutputWindow.DebugCategory}");
CompilerMessageView compilerMessageView = (CompilerMessageView)WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).PadContent;
compilerMessageView.AddCategory(debugCategory);
}
}
public static void ClearDebugMessages()
{
EnsureDebugCategory();
debugCategory.ClearText();
}
public static void PrintDebugMessage(string msg)
{
try {
EnsureDebugCategory();
debugCategory.AppendText(msg);
} catch (Exception) {}
}
static string oldLayoutConfiguration = "Default";
static void HandleDebugStopped(object sender, EventArgs e)
{
// LayoutConfiguration.CurrentLayoutName = oldLayoutConfiguration;
//// Alex: if stopped - kill process which might be running or stuck
if (standardProcess != null) {
standardProcess.Kill();
standardProcess.Close();
standardProcess = null;
}
IDebugger debugger = CurrentDebugger;
if (debugger != null) {
debugger.Stop();
}
debugger.DebugStopped -= new EventHandler(HandleDebugStopped);
debugger.Dispose();
isRunning = false;
}
#region ICSharpCode.Core.IService interface implementation
public static void InitializeService()
{
AddInTreeNode treeNode = null;
try {
treeNode = AddInTree.GetTreeNode("/SharpDevelop/Services/DebuggerService/Debugger");
} catch (Exception) {
}
if (treeNode != null) {
debugger = treeNode.BuildChildItems(null);
}
ProjectService.SolutionLoaded += new SolutionEventHandler(ClearOnCombineEvent);
}
static void DebuggerServiceStarted(object sender, EventArgs e)
{
EnsureDebugCategory();
debugCategory.ClearText();
CompilerMessageView compilerMessageView = (CompilerMessageView)WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).PadContent;
compilerMessageView.SelectCategory("Debug");
}
static void ClearOnCombineEvent(object sender, SolutionEventArgs e)
{
EnsureDebugCategory();
debugCategory.ClearText();
}
#endregion
public static void GotoSourceFile(string fileName, int lineNumber, int column)
{
FileService.JumpToFilePosition(fileName, lineNumber, column);
}
public static void StartWithoutDebugging(System.Diagnostics.ProcessStartInfo psi)
{
if (IsProcessRuning) {
return;
}
try {
standardProcess = new System.Diagnostics.Process();
standardProcess.StartInfo = psi;
standardProcess.Exited += new EventHandler(StandardProcessExited);
standardProcess.EnableRaisingEvents = true;
standardProcess.Start();
isRunning = true;
} catch (Exception e) {
MessageService.ShowError(e, "Can't execute " + "\"" + psi.FileName + "\"\n");
}
}
public static void StartWithoutDebugging(string fileName, string workingDirectory, string arguments)
{
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments);
startInfo.WorkingDirectory = workingDirectory;
startInfo.UseShellExecute = false;
StartWithoutDebugging(startInfo);
}
public static void Start(string fileName, string workingDirectory, string arguments)
{
if (IsProcessRuning) {
return;
}
oldLayoutConfiguration = LayoutConfiguration.CurrentLayoutName;
// LayoutConfiguration.CurrentLayoutName = "Debug";
IDebugger debugger = CurrentDebugger;
if (debugger != null) {
debugger.Start(fileName, workingDirectory, arguments);
debugger.DebugStopped += new EventHandler(HandleDebugStopped);
}
// lock (breakpoints) {
// foreach (Breakpoint breakpoint in breakpoints) {
// if (breakpoint.Enabled) {
// brea.AddBreakpoint(fileName, breakpoint.FileName, breakpoint.Line);
// }
// }
// }
isRunning = true;
}
public static void Break()
{
IDebugger debugger = CurrentDebugger;
if (debugger != null && debugger.SupportsExecutionControl) {
debugger.Break();
}
}
public static void Continue()
{
IDebugger debugger = CurrentDebugger;
if (debugger != null && debugger.SupportsExecutionControl) {
debugger.Continue();
}
}
public static void Step(bool stepInto)
{
IDebugger debugger = CurrentDebugger;
if (debugger == null || !debugger.SupportsStepping) {
return;
}
if (stepInto) {
debugger.StepInto();
} else {
debugger.StepOver();
}
}
public static void StepOut()
{
IDebugger debugger = CurrentDebugger;
if (debugger == null || !debugger.SupportsStepping) {
return;
}
debugger.StepOut();
}
public static void Stop()
{
if (standardProcess != null) {
// OnTextMessage(new TextMessageEventArgs(String.Format("Killing {0}{1}\n",standardProcess.ProcessName,Environment.NewLine)));
standardProcess.Exited -= new EventHandler(StandardProcessExited);
standardProcess.Kill();
standardProcess.Close();
standardProcess.Dispose();
standardProcess = null;
} else {
IDebugger debugger = CurrentDebugger;
if (debugger != null) {
debugger.Stop();
}
}
isRunning = false;
}
static void StandardProcessExited(object sender, EventArgs e)
{
standardProcess.Exited -= new EventHandler(StandardProcessExited);
standardProcess.Dispose();
standardProcess = null;
isRunning = false;
}
// protected override void OnException(ExceptionEventArgs e)
// {
// base.OnException(e);
// OnTextMessage(new TextMessageEventArgs("Got Exception\n"));
// StopDebugger();
// }
//
// protected override void OnProcessExited(ProcessEventArgs e)
// {
// OnTextMessage(new TextMessageEventArgs(String.Format("The program '[{1}] {0}' exited with code {2}.{3}\n",
// "Unknown",
// e.Process.ID,
// "Unknown",Environment.NewLine)));
// base.OnProcessExited(e);
// }
// protected override void OnModuleLoaded(ModuleEventArgs e)
// {
// OnTextMessage(new TextMessageEventArgs(String.Format("'{0}' : '{1}' loaded, {2}.{3}\n",
// "Unknown",
// e.Module.Name,
// "Unknown",Environment.NewLine)));
// base.OnModuleLoaded(e);
// }
public static event EventHandler BreakPointChanged;
public static event EventHandler BreakPointAdded;
public static event EventHandler BreakPointRemoved;
static void OnBreakPointChanged(EventArgs e)
{
if (BreakPointChanged != null) {
BreakPointChanged(null, e);
}
}
static void OnBreakPointAdded(EventArgs e)
{
if (BreakPointAdded != null) {
BreakPointAdded(null, e);
}
}
static void OnBreakPointRemoved(EventArgs e)
{
if (BreakPointRemoved != null) {
BreakPointRemoved(null, e);
}
}
static List<Breakpoint> breakpoints = new List<Breakpoint>();
public static IList<Breakpoint> Breakpoints {
get {
return breakpoints;
}
}
public static void ToggleBreakpointAt(string fileName, int line, int column)
{
foreach(Breakpoint b in breakpoints) {
if (b.FileName == fileName && b.LineNumber == line) {
breakpoints.Remove(b);
OnBreakPointRemoved(EventArgs.Empty);
return;
}
}
breakpoints.Add(new Breakpoint(fileName, line));
OnBreakPointAdded(EventArgs.Empty);
}
class BreakpointMarker: TextMarker
{
public BreakpointMarker(int offset, int length, TextMarkerType textMarkerType, Color color, Color foreColor):base(offset, length, textMarkerType, color, foreColor)
{
}
}
class CurrentLineMarker: TextMarker
{
public CurrentLineMarker(int offset, int length, TextMarkerType textMarkerType, Color color, Color foreColor):base(offset, length, textMarkerType, color, foreColor)
{
}
}
public static void InitializeService2()
{
WorkbenchSingleton.WorkbenchCreated += new EventHandler(WorkspaceCreated);
}
static void WorkspaceCreated(object sender, EventArgs args)
{
WorkbenchSingleton.Workbench.ViewOpened += new ViewContentEventHandler(ViewContentOpened);
WorkbenchSingleton.Workbench.ViewClosed += new ViewContentEventHandler(ViewContentClosed);
}
static void ViewContentOpened(object sender, ViewContentEventArgs e)
{
if (e.Content.Control is TextEditor.TextEditorControl) {
TextArea textArea = ((TextEditor.TextEditorControl)e.Content.Control).ActiveTextAreaControl.TextArea;
textArea.IconBarMargin.MouseDown += new MarginMouseEventHandler(IconBarMouseDown);
textArea.IconBarMargin.Painted += new MarginPaintEventHandler(PaintIconBar);
textArea.MouseMove += new MouseEventHandler(TextAreaMouseMove);
RefreshBreakpointMarkersInEditor(textArea.MotherTextEditorControl);
}
}
static void ViewContentClosed(object sender, ViewContentEventArgs e)
{
if (e.Content.Control is TextEditor.TextEditorControl) {
TextArea textArea = ((TextEditor.TextEditorControl)e.Content.Control).ActiveTextAreaControl.TextArea;
textArea.IconBarMargin.MouseDown -= new MarginMouseEventHandler(IconBarMouseDown);
textArea.IconBarMargin.Painted -= new MarginPaintEventHandler(PaintIconBar);
textArea.MouseMove -= new MouseEventHandler(TextAreaMouseMove);
}
}
static TextMarker currentLineMarker;
static IDocument currentLineMarkerParent;
static public void RemoveCurrentLineMarker()
{
if (currentLineMarker != null) {
currentLineMarkerParent.MarkerStrategy.TextMarker.Remove(currentLineMarker);
currentLineMarkerParent.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
currentLineMarkerParent.CommitUpdate();
currentLineMarkerParent = null;
currentLineMarker = null;
}
}
static public void JumpToCurrentLine(string SourceFullFilename, int StartLine, int StartColumn, int EndLine, int EndColumn)
{
RemoveCurrentLineMarker();
FileService.OpenFile(SourceFullFilename);
IWorkbenchWindow window = FileService.GetOpenFile(SourceFullFilename);
if (window != null) {
IViewContent content = window.ViewContent;
if (content is IPositionable) {
((IPositionable)content).JumpTo((int)StartLine - 1, (int)StartColumn - 1);
}
if (content.Control is TextEditorControl) {
IDocument document = ((TextEditorControl)content.Control).Document;
LineSegment line = document.GetLineSegment((int)StartLine - 1);
int offset = line.Offset + (int)StartColumn;
currentLineMarker = new CurrentLineMarker(offset, (int)EndColumn - (int)StartColumn, TextMarkerType.SolidBlock, Color.Yellow, Color.Blue);
currentLineMarkerParent = document;
currentLineMarkerParent.MarkerStrategy.TextMarker.Add(currentLineMarker);
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
document.CommitUpdate();
}
}
}
static void IconBarMouseDown(AbstractMargin iconBar, Point mousepos, MouseButtons mouseButtons)
{
Rectangle viewRect = iconBar.TextArea.TextView.DrawingPosition;
Point logicPos = iconBar.TextArea.TextView.GetLogicalPosition(0, mousepos.Y - viewRect.Top);
if (logicPos.Y >= 0 && logicPos.Y < iconBar.TextArea.Document.TotalNumberOfLines) {
ToggleBreakpointAt(iconBar.TextArea.MotherTextEditorControl.FileName , logicPos.Y + 1, 0);
RefreshBreakpointMarkersInEditor(iconBar.TextArea.MotherTextEditorControl);
iconBar.TextArea.Refresh(iconBar);
}
}
static void RefreshBreakpointMarkersInEditor(TextEditorControl textEditor)
{
IDocument document = textEditor.Document;
System.Collections.Generic.List<ICSharpCode.TextEditor.Document.TextMarker> markers = textEditor.Document.MarkerStrategy.TextMarker;
// Remove all breakpoint markers
for (int i = 0; i < markers.Count;) {
if (markers[i] is BreakpointMarker) {
markers.RemoveAt(i);
} else {
i++; // Check next one
}
}
// Add breakpoint markers
foreach (Breakpoint b in Breakpoints) {
if (b.FileName.ToLower() == textEditor.FileName.ToLower()) {
LineSegment lineSeg = document.GetLineSegment((int)b.LineNumber - 1);
document.MarkerStrategy.TextMarker.Add(new BreakpointMarker(lineSeg.Offset, lineSeg.Length , TextMarkerType.SolidBlock, Color.Red, Color.White));
}
}
// Perform editor update
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
document.CommitUpdate();
}
/// <summary>
/// Draw Breakpoint icon and the yellow arrow in the margin
/// </summary>
static void PaintIconBar(AbstractMargin iconBar, Graphics g, Rectangle rect)
{
foreach (Breakpoint breakpoint in Breakpoints) {
if (Path.GetFullPath(breakpoint.FileName) == Path.GetFullPath(iconBar.TextArea.MotherTextEditorControl.FileName)) {
int lineNumber = iconBar.TextArea.Document.GetVisibleLine((int)breakpoint.LineNumber - 1);
int yPos = (int)(lineNumber * iconBar.TextArea.TextView.FontHeight) - iconBar.TextArea.VirtualTop.Y;
if (yPos >= rect.Y && yPos <= rect.Bottom) {
((IconBarMargin)iconBar).DrawBreakpoint(g, yPos, breakpoint.IsEnabled);
}
}
}
foreach (TextMarker textMarker in iconBar.TextArea.Document.MarkerStrategy.TextMarker) {
CurrentLineMarker currentLineMarker = textMarker as CurrentLineMarker;
if (currentLineMarker != null) {
int lineNumber = iconBar.TextArea.Document.GetVisibleLine((int)iconBar.TextArea.Document.GetLineNumberForOffset(currentLineMarker.Offset));
int yPos = (int)(lineNumber * iconBar.TextArea.TextView.FontHeight) - iconBar.TextArea.VirtualTop.Y;
if (yPos >= rect.Y && yPos <= rect.Bottom) {
((IconBarMargin)iconBar).DrawArrow(g, yPos);
}
}
}
}
/// <summary>
/// This function shows variable values as tooltips
/// </summary>
static void TextAreaMouseMove(object sender, MouseEventArgs args)
{
TextArea textArea = (TextArea)sender;
Point mousepos = textArea.PointToClient(Control.MousePosition);
Rectangle viewRect = textArea.TextView.DrawingPosition;
if (viewRect.Contains(mousepos)) {
Point logicPos = textArea.TextView.GetLogicalPosition(mousepos.X - viewRect.Left,
mousepos.Y - viewRect.Top);
if (logicPos.Y >= 0 && logicPos.Y < textArea.Document.TotalNumberOfLines) {
IDocument doc = textArea.Document;
LineSegment seg = doc.GetLineSegment(logicPos.Y);
string line = doc.GetText(seg.Offset, seg.Length);
int startIndex = 0;
int length = 0;
string expression = String.Empty;
for(int index = 0; index < seg.Length; index++) {
char chr = line[index];
if ((Char.IsLetterOrDigit(chr) || chr == '_' || chr == '.') == false || // invalid character
(chr == '.' && logicPos.X <= index)) { // Start of sub-expression at the right side of cursor
// End of expresion...
if ((startIndex <= logicPos.X && logicPos.X <= index) && // Correct position
(startIndex != index)) { // Actually something
length = index - startIndex;
expression = line.Substring(startIndex, length);
break;
} else {
// Let's try next one...
startIndex = index + 1;
}
}
}
//Console.WriteLine("MouseMove@" + logicPos + ":" + expression);
if (expression != String.Empty) {
// Look if it is variable
try {
//value = selectedThread.LocalVariables[expresion].Value.ToString();
ResolveResult result = ParserService.Resolve(expression, logicPos.Y, startIndex, textArea.MotherTextEditorControl.FileName, doc.TextContent);
string value = GetText(result);
if (value != null) {
textArea.SetToolTip(value);
}
} catch (Exception e) {
Console.Beep();
Console.WriteLine();
Console.WriteLine(e);
}
}
}
}
}
static string GetText(ResolveResult result)
{
if (result == null)
return null;
IAmbience ambience = AmbienceService.CurrentAmbience;
ambience.ConversionFlags = ConversionFlags.StandardConversionFlags
| ConversionFlags.ShowAccessibility;
if (result is MemberResolveResult) {
MemberResolveResult rr = (MemberResolveResult)result;
IMember member = rr.ResolvedMember;
if (member is IIndexer)
return ambience.Convert(member as IIndexer);
if (member is IField)
return ambience.Convert(member as IField);
if (member is IProperty)
return ambience.Convert(member as IProperty);
if (member is IEvent)
return ambience.Convert(member as IEvent);
if (member is IMethod)
return ambience.Convert(member as IMethod);
return "unknown member " + member.ToString();
} else if (result is LocalResolveResult) {
LocalResolveResult rr = (LocalResolveResult)result;
ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedNames
| ConversionFlags.ShowReturnType
| ConversionFlags.QualifiedNamesOnlyForReturnTypes;
if (rr.IsParameter)
return "parameter " + ambience.Convert(rr.Field);
else
return "local variable " + ambience.Convert(rr.Field);
} else if (result is NamespaceResolveResult) {
return "namespace " + ((NamespaceResolveResult)result).Name;
} else if (result is TypeResolveResult) {
return ambience.Convert(((TypeResolveResult)result).ResolvedClass);
} else {
if (result.ResolvedType == null)
return null;
else
return "expression of type " + ambience.Convert(result.ResolvedType);
}
}
}
}