~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.Text;
 
7
using System.Windows.Forms;
 
8
using ICSharpCode.Core;
 
9
using ICSharpCode.NRefactory;
 
10
using ICSharpCode.SharpDevelop.Bookmarks;
 
11
using ICSharpCode.SharpDevelop.Dom;
 
12
using ICSharpCode.SharpDevelop.Dom.VBNet;
 
13
using ICSharpCode.SharpDevelop.Editor;
 
14
using ICSharpCode.SharpDevelop.Gui;
 
15
using ICSharpCode.SharpDevelop.Project;
 
16
 
 
17
namespace ICSharpCode.SharpDevelop.Debugging
 
18
{
 
19
        public static class DebuggerService
 
20
        {
 
21
                static IDebugger   currentDebugger;
 
22
                static DebuggerDescriptor[] debuggers;
 
23
                static string      oldLayoutConfiguration = "Default";
 
24
 
 
25
                static DebuggerService()
 
26
                {
 
27
                        ProjectService.SolutionLoaded += delegate {
 
28
                                ClearDebugMessages();
 
29
                        };
 
30
                        
 
31
                        ProjectService.BeforeSolutionClosing += OnBeforeSolutionClosing;
 
32
                        
 
33
                        BookmarkManager.Added   += BookmarkAdded;
 
34
                        BookmarkManager.Removed += BookmarkRemoved;
 
35
                }
 
36
                
 
37
                static void GetDescriptors()
 
38
                {
 
39
                        if (debuggers == null) {
 
40
                                debuggers = AddInTree.BuildItems<DebuggerDescriptor>("/SharpDevelop/Services/DebuggerService/Debugger", null, false).ToArray();
 
41
                        }
 
42
                }
 
43
                
 
44
                static IDebugger GetCompatibleDebugger()
 
45
                {
 
46
                        GetDescriptors();
 
47
                        IProject project = null;
 
48
                        if (ProjectService.OpenSolution != null) {
 
49
                                project = ProjectService.OpenSolution.StartupProject;
 
50
                        }
 
51
                        foreach (DebuggerDescriptor d in debuggers) {
 
52
                                if (d.Debugger != null && d.Debugger.CanDebug(project)) {
 
53
                                        return d.Debugger;
 
54
                                }
 
55
                        }
 
56
                        return new DefaultDebugger();
 
57
                }
 
58
                
 
59
                /// <summary>
 
60
                /// Gets the current debugger. The debugger addin is loaded on demand; so if you
 
61
                /// just want to check a property like IsDebugging, check <see cref="IsDebuggerLoaded"/>
 
62
                /// before using this property.
 
63
                /// </summary>
 
64
                public static IDebugger CurrentDebugger {
 
65
                        get {
 
66
                                if (currentDebugger == null) {
 
67
                                        currentDebugger = GetCompatibleDebugger();
 
68
                                        currentDebugger.DebugStarting += new EventHandler(OnDebugStarting);
 
69
                                        currentDebugger.DebugStarted += new EventHandler(OnDebugStarted);
 
70
                                        currentDebugger.DebugStopped += new EventHandler(OnDebugStopped);
 
71
                                }
 
72
                                return currentDebugger;
 
73
                        }
 
74
                }
 
75
                
 
76
                public static DebuggerDescriptor Descriptor {
 
77
                        get {
 
78
                                GetDescriptors();
 
79
                                if (debuggers.Length > 0)
 
80
                                        return debuggers[0];
 
81
                                return null;
 
82
                        }
 
83
                }
 
84
                
 
85
                /// <summary>
 
86
                /// Returns true if debugger is already loaded.
 
87
                /// </summary>
 
88
                public static bool IsDebuggerLoaded {
 
89
                        get {
 
90
                                return currentDebugger != null;
 
91
                        }
 
92
                }
 
93
                
 
94
                static bool debuggerStarted;
 
95
                
 
96
                /// <summary>
 
97
                /// Gets whether the debugger is currently active.
 
98
                /// </summary>
 
99
                public static bool IsDebuggerStarted {
 
100
                        get { return debuggerStarted; }
 
101
                }
 
102
                
 
103
                public static event EventHandler DebugStarting;
 
104
                public static event EventHandler DebugStarted;
 
105
                public static event EventHandler DebugStopped;
 
106
                
 
107
                static IAnalyticsMonitorTrackedFeature debugFeature;
 
108
                
 
109
                static void OnDebugStarting(object sender, EventArgs e)
 
110
                {
 
111
                        WorkbenchSingleton.Workbench.WorkbenchLayout.StoreConfiguration();
 
112
                        LayoutConfiguration.CurrentLayoutName = "Debug";
 
113
                        
 
114
                        debugFeature = AnalyticsMonitorService.TrackFeature("Debugger");
 
115
                        
 
116
                        ClearDebugMessages();
 
117
                        
 
118
                        if (DebugStarting != null)
 
119
                                DebugStarting(null, e);
 
120
                }
 
121
                
 
122
                static void OnDebugStarted(object sender, EventArgs e)
 
123
                {
 
124
                        debuggerStarted = true;
 
125
                        if (DebugStarted != null)
 
126
                                DebugStarted(null, e);
 
127
                }
 
128
                
 
129
                static void OnDebugStopped(object sender, EventArgs e)
 
130
                {
 
131
                        debuggerStarted = false;
 
132
                        if (debugFeature != null)
 
133
                                debugFeature.EndTracking();
 
134
                        
 
135
                        RemoveCurrentLineMarker();
 
136
                        WorkbenchSingleton.Workbench.WorkbenchLayout.StoreConfiguration();
 
137
                        LayoutConfiguration.CurrentLayoutName = oldLayoutConfiguration;
 
138
                        if (DebugStopped != null)
 
139
                                DebugStopped(null, e);
 
140
                }
 
141
                
 
142
                static MessageViewCategory debugCategory = null;
 
143
                
 
144
                static void EnsureDebugCategory()
 
145
                {
 
146
                        if (debugCategory == null) {
 
147
                                MessageViewCategory.Create(ref debugCategory, "Debug", "${res:MainWindow.Windows.OutputWindow.DebugCategory}");
 
148
                        }
 
149
                }
 
150
 
 
151
                public static void ClearDebugMessages()
 
152
                {
 
153
                        EnsureDebugCategory();
 
154
                        debugCategory.ClearText();
 
155
                }
 
156
 
 
157
                public static void PrintDebugMessage(string msg)
 
158
                {
 
159
                        EnsureDebugCategory();
 
160
                        debugCategory.AppendText(msg);
 
161
                }
 
162
 
 
163
                public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointChanged;
 
164
                public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointAdded;
 
165
                public static event EventHandler<BreakpointBookmarkEventArgs> BreakPointRemoved;
 
166
                
 
167
                static void OnBreakPointChanged(BreakpointBookmarkEventArgs e)
 
168
                {
 
169
                        if (BreakPointChanged != null) {
 
170
                                BreakPointChanged(null, e);
 
171
                        }
 
172
                }
 
173
                
 
174
                static void OnBreakPointAdded(BreakpointBookmarkEventArgs e)
 
175
                {
 
176
                        if (BreakPointAdded != null) {
 
177
                                BreakPointAdded(null, e);
 
178
                        }
 
179
                }
 
180
                
 
181
                static void OnBreakPointRemoved(BreakpointBookmarkEventArgs e)
 
182
                {
 
183
                        if (BreakPointRemoved != null) {
 
184
                                BreakPointRemoved(null, e);
 
185
                        }
 
186
                }
 
187
                
 
188
                public static IList<BreakpointBookmark> Breakpoints {
 
189
                        get {
 
190
                                List<BreakpointBookmark> breakpoints = new List<BreakpointBookmark>();
 
191
                                foreach (SDBookmark bookmark in BookmarkManager.Bookmarks) {
 
192
                                        BreakpointBookmark breakpoint = bookmark as BreakpointBookmark;
 
193
                                        if (breakpoint != null) {
 
194
                                                breakpoints.Add(breakpoint);
 
195
                                        }
 
196
                                }
 
197
                                return breakpoints.AsReadOnly();
 
198
                        }
 
199
                }
 
200
                
 
201
                static void BookmarkAdded(object sender, BookmarkEventArgs e)
 
202
                {
 
203
                        BreakpointBookmark bb = e.Bookmark as BreakpointBookmark;
 
204
                        if (bb != null) {
 
205
                                bb.LineNumberChanged += BookmarkChanged;
 
206
                                OnBreakPointAdded(new BreakpointBookmarkEventArgs(bb));
 
207
                        }
 
208
                }
 
209
                
 
210
                static void BookmarkRemoved(object sender, BookmarkEventArgs e)
 
211
                {
 
212
                        BreakpointBookmark bb = e.Bookmark as BreakpointBookmark;
 
213
                        if (bb != null) {
 
214
                                bb.RemoveMarker();
 
215
                                OnBreakPointRemoved(new BreakpointBookmarkEventArgs(bb));
 
216
                        }
 
217
                }
 
218
                
 
219
                static void BookmarkChanged(object sender, EventArgs e)
 
220
                {
 
221
                        BreakpointBookmark bb = sender as BreakpointBookmark;
 
222
                        if (bb != null) {
 
223
                                OnBreakPointChanged(new BreakpointBookmarkEventArgs(bb));
 
224
                        }
 
225
                }
 
226
                
 
227
                static void OnBeforeSolutionClosing(object sender, SolutionCancelEventArgs e)
 
228
                {
 
229
                        if (currentDebugger == null)
 
230
                                return;
 
231
                        
 
232
                        if (currentDebugger.IsDebugging) {
 
233
                                string caption = StringParser.Parse("${res:XML.MainMenu.DebugMenu.Stop}");
 
234
                                string message = StringParser.Parse("${res:MainWindow.Windows.Debug.StopDebugging.Message}");
 
235
                                string[] buttonLabels = new string[] { StringParser.Parse("${res:Global.Yes}"), StringParser.Parse("${res:Global.No}") };
 
236
                                int result = MessageService.ShowCustomDialog(caption,
 
237
                                                                             message,
 
238
                                                                             0, // yes
 
239
                                                                             1, // no
 
240
                                                                             buttonLabels);
 
241
                                
 
242
                                if (result == 0) {
 
243
                                        currentDebugger.Stop();
 
244
                                } else {
 
245
                                        e.Cancel = true;
 
246
                                }
 
247
                        }
 
248
                }
 
249
                
 
250
                public static void ToggleBreakpointAt(ITextEditor editor, int lineNumber)
 
251
                {
 
252
                        BookmarkManager.ToggleBookmark(
 
253
                                editor, lineNumber,
 
254
                                b => b.CanToggle && b is BreakpointBookmark,
 
255
                                location => new BreakpointBookmark(editor.FileName, location, BreakpointAction.Break, "", ""));
 
256
                }
 
257
                
 
258
                /* TODO: reimplement this stuff
 
259
                static void ViewContentOpened(object sender, ViewContentEventArgs e)
 
260
                {
 
261
                                textArea.IconBarMargin.MouseDown += IconBarMouseDown;
 
262
                                textArea.ToolTipRequest          += TextAreaToolTipRequest;
 
263
                                textArea.MouseLeave              += TextAreaMouseLeave;
 
264
                }*/
 
265
                
 
266
                public static void RemoveCurrentLineMarker()
 
267
                {
 
268
                        CurrentLineBookmark.Remove();
 
269
                }
 
270
                
 
271
                public static void JumpToCurrentLine(string SourceFullFilename, int StartLine, int StartColumn, int EndLine, int EndColumn)
 
272
                {
 
273
                        IViewContent viewContent = FileService.OpenFile(SourceFullFilename);
 
274
                        if (viewContent is ITextEditorProvider)
 
275
                                ((ITextEditorProvider)viewContent).TextEditor.JumpTo(StartLine, StartColumn);
 
276
                        CurrentLineBookmark.SetPosition(viewContent, StartLine, StartColumn, EndLine, EndColumn);
 
277
                }
 
278
                
 
279
                #region Tool tips
 
280
                /// <summary>
 
281
                /// Gets debugger tooltip information for the specified position.
 
282
                /// A descriptive string for the element or a DebuggerTooltipControl
 
283
                /// showing its current value (when in debugging mode) can be returned
 
284
                /// through the ToolTipRequestEventArgs.SetTooltip() method.
 
285
                /// </summary>
 
286
                internal static void HandleToolTipRequest(ToolTipRequestEventArgs e)
 
287
                {
 
288
                        if (!e.InDocument)
 
289
                                return;
 
290
                        Location logicPos = e.LogicalPosition;
 
291
                        var doc = e.Editor.Document;
 
292
                        IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(e.Editor.FileName);
 
293
                        if (expressionFinder == null)
 
294
                                return;
 
295
                        var currentLine = doc.GetLine(logicPos.Y);
 
296
                        if (logicPos.X > currentLine.Length)
 
297
                                return;
 
298
                        string textContent = doc.Text;
 
299
                        ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, doc.PositionToOffset(logicPos.Line, logicPos.Column));
 
300
                        string expression = (expressionResult.Expression ?? "").Trim();
 
301
                        if (expression.Length > 0) {
 
302
                                // Look if it is variable
 
303
                                ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y, logicPos.X, e.Editor.FileName, textContent);
 
304
                                bool debuggerCanShowValue;
 
305
                                string toolTipText = GetText(result, expression, out debuggerCanShowValue);
 
306
                                if (Control.ModifierKeys == Keys.Control) {
 
307
                                        toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText;
 
308
                                        debuggerCanShowValue = false;
 
309
                                }
 
310
                                if (toolTipText != null) {
 
311
                                        if (debuggerCanShowValue && currentDebugger != null) {
 
312
                                                object toolTip = currentDebugger.GetTooltipControl(e.LogicalPosition, expressionResult.Expression);
 
313
                                                if (toolTip != null)
 
314
                                                        e.SetToolTip(toolTip);
 
315
                                                else
 
316
                                                        e.SetToolTip(toolTipText);
 
317
                                        } else {
 
318
                                                e.SetToolTip(toolTipText);
 
319
                                        }
 
320
                                }
 
321
                        } else {
 
322
                                #if DEBUG
 
323
                                if (Control.ModifierKeys == Keys.Control) {
 
324
                                        e.SetToolTip("no expr: " + expressionResult.ToString());
 
325
                                }
 
326
                                #endif
 
327
                        }
 
328
                }
 
329
                
 
330
                static string GetText(ResolveResult result, string expression, out bool debuggerCanShowValue)
 
331
                {
 
332
                        debuggerCanShowValue = false;
 
333
                        if (result == null) {
 
334
                                // when pressing control, show the expression even when it could not be resolved
 
335
                                return (Control.ModifierKeys == Keys.Control) ? "" : null;
 
336
                        }
 
337
                        if (result is MixedResolveResult)
 
338
                                return GetText(((MixedResolveResult)result).PrimaryResult, expression, out debuggerCanShowValue);
 
339
                        else if (result is DelegateCallResolveResult)
 
340
                                return GetText(((DelegateCallResolveResult)result).Target, expression, out debuggerCanShowValue);
 
341
                        
 
342
                        IAmbience ambience = AmbienceService.GetCurrentAmbience();
 
343
                        ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.UseFullyQualifiedMemberNames;
 
344
                        if (result is MemberResolveResult) {
 
345
                                return GetMemberText(ambience, ((MemberResolveResult)result).ResolvedMember, expression, out debuggerCanShowValue);
 
346
                        } else if (result is LocalResolveResult) {
 
347
                                LocalResolveResult rr = (LocalResolveResult)result;
 
348
                                ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedTypeNames
 
349
                                        | ConversionFlags.ShowReturnType | ConversionFlags.ShowDefinitionKeyWord;
 
350
                                StringBuilder b = new StringBuilder();
 
351
                                if (rr.IsParameter)
 
352
                                        b.Append("parameter ");
 
353
                                else
 
354
                                        b.Append("local variable ");
 
355
                                b.Append(ambience.Convert(rr.Field));
 
356
                                if (currentDebugger != null) {
 
357
                                        string currentValue = currentDebugger.GetValueAsString(rr.VariableName);
 
358
                                        if (currentValue != null) {
 
359
                                                debuggerCanShowValue = true;
 
360
                                                b.Append(" = ");
 
361
                                                if (currentValue.Length > 256)
 
362
                                                        currentValue = currentValue.Substring(0, 256) + "...";
 
363
                                                b.Append(currentValue);
 
364
                                        }
 
365
                                }
 
366
                                return b.ToString();
 
367
                        } else if (result is NamespaceResolveResult) {
 
368
                                return "namespace " + ((NamespaceResolveResult)result).Name;
 
369
                        } else if (result is TypeResolveResult) {
 
370
                                IClass c = ((TypeResolveResult)result).ResolvedClass;
 
371
                                if (c != null)
 
372
                                        return GetMemberText(ambience, c, expression, out debuggerCanShowValue);
 
373
                                else
 
374
                                        return ambience.Convert(result.ResolvedType);
 
375
                        } else if (result is MethodGroupResolveResult) {
 
376
                                MethodGroupResolveResult mrr = result as MethodGroupResolveResult;
 
377
                                IMethod m = mrr.GetMethodIfSingleOverload();
 
378
                                IMethod m2 = mrr.GetMethodWithEmptyParameterList();
 
379
                                if (m != null)
 
380
                                        return GetMemberText(ambience, m, expression, out debuggerCanShowValue);
 
381
                                else if (ambience is VBNetAmbience && m2 != null)
 
382
                                        return GetMemberText(ambience, m2, expression, out debuggerCanShowValue);
 
383
                                else
 
384
                                        return "Overload of " + ambience.Convert(mrr.ContainingType) + "." + mrr.Name;
 
385
                        } else {
 
386
                                if (Control.ModifierKeys == Keys.Control) {
 
387
                                        if (result.ResolvedType != null)
 
388
                                                return "expression of type " + ambience.Convert(result.ResolvedType);
 
389
                                        else
 
390
                                                return "ResolveResult without ResolvedType";
 
391
                                } else {
 
392
                                        return null;
 
393
                                }
 
394
                        }
 
395
                }
 
396
                
 
397
                static string GetMemberText(IAmbience ambience, IEntity member, string expression, out bool debuggerCanShowValue)
 
398
                {
 
399
                        bool tryDisplayValue = false;
 
400
                        debuggerCanShowValue = false;
 
401
                        StringBuilder text = new StringBuilder();
 
402
                        if (member is IField) {
 
403
                                text.Append(ambience.Convert(member as IField));
 
404
                                tryDisplayValue = true;
 
405
                        } else if (member is IProperty) {
 
406
                                text.Append(ambience.Convert(member as IProperty));
 
407
                                tryDisplayValue = true;
 
408
                        } else if (member is IEvent) {
 
409
                                text.Append(ambience.Convert(member as IEvent));
 
410
                        } else if (member is IMethod) {
 
411
                                text.Append(ambience.Convert(member as IMethod));
 
412
                        } else if (member is IClass) {
 
413
                                text.Append(ambience.Convert(member as IClass));
 
414
                        } else {
 
415
                                text.Append("unknown member ");
 
416
                                text.Append(member.ToString());
 
417
                        }
 
418
                        if (tryDisplayValue && currentDebugger != null) {
 
419
                                LoggingService.Info("asking debugger for value of '" + expression + "'");
 
420
                                string currentValue = currentDebugger.GetValueAsString(expression);
 
421
                                if (currentValue != null) {
 
422
                                        debuggerCanShowValue = true;
 
423
                                        text.Append(" = ");
 
424
                                        text.Append(currentValue);
 
425
                                }
 
426
                        }
 
427
                        string documentation = member.Documentation;
 
428
                        if (documentation != null && documentation.Length > 0) {
 
429
                                text.Append('\n');
 
430
                                text.Append(ICSharpCode.SharpDevelop.Editor.CodeCompletion.CodeCompletionItem.ConvertDocumentation(documentation));
 
431
                        }
 
432
                        return text.ToString();
 
433
                }
 
434
                #endregion
 
435
        }
 
436
        
 
437
        /// <summary>
 
438
        /// Provides the default debugger tooltips on the text area.
 
439
        /// </summary>
 
440
        /// <remarks>
 
441
        /// This class must be public because it is accessed via the AddInTree.
 
442
        /// </remarks>
 
443
        public class DebuggerTextAreaToolTipProvider : ITextAreaToolTipProvider
 
444
        {
 
445
                public void HandleToolTipRequest(ToolTipRequestEventArgs e)
 
446
                {
 
447
                        DebuggerService.HandleToolTipRequest(e);
 
448
                }
 
449
        }
 
450
}