Browse Source

Merge branch 'Debugger' of github.com:icsharpcode/SharpDevelop into newNR

newNRvisualizers
Siegfried Pammer 13 years ago
parent
commit
db35bad84f
  1. 2
      SharpDevelop.Tests.sln
  2. 7
      src/AddIns/Analysis/UnitTesting/Test/Utils/MockDebugger.cs
  3. 7
      src/AddIns/BackendBindings/Scripting/Test/Utils/MockDebugger.cs
  4. 72
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  5. 76
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  6. 92
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs
  7. 7
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs
  8. 5
      src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs
  9. 68
      src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs
  10. 210
      src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.cs
  11. 41
      src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml
  12. 306
      src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml.cs
  13. 127
      src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs
  14. 128
      src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs
  15. 120
      src/AddIns/Debugger/Debugger.AddIn/Pads/Common/AutoCompleteTextBox.cs
  16. 99
      src/AddIns/Debugger/Debugger.AddIn/Pads/Common/CommonResources.xaml
  17. 53
      src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs
  18. 22
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/ConditionCell.xaml
  19. 196
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/ConditionCell.xaml.cs
  20. 28
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/Converters.cs
  21. 82
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml
  22. 94
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs
  23. 175
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchListAutoCompleteCell.cs
  24. 11
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchListAutoCompleteCell.xaml
  25. 85
      src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerPad.cs
  26. 120
      src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs
  27. 88
      src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs
  28. 331
      src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs
  29. 72
      src/AddIns/Debugger/Debugger.AddIn/Pads/ObjectGraphPad.cs
  30. 114
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackFrameModel.cs
  31. 91
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs
  32. 9
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ThreadStack.xaml.cs
  33. 65
      src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.Menu.cs
  34. 154
      src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.cs
  35. 138
      src/AddIns/Debugger/Debugger.AddIn/Pads/ThreadsPad.cs
  36. 35
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchInputBox.xaml
  37. 170
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchInputBox.xaml.cs
  38. 230
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
  39. 49
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
  40. 2
      src/AddIns/Debugger/Debugger.AddIn/Service/DebuggeeExceptionForm.cs
  41. 82
      src/AddIns/Debugger/Debugger.AddIn/Service/RemotingConfigurationHelpper.cs
  42. 21
      src/AddIns/Debugger/Debugger.AddIn/Service/RunToCursorCommand.cs
  43. 2
      src/AddIns/Debugger/Debugger.AddIn/Service/SetCurrentStatementCommand.cs
  44. 640
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  45. 102
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs
  46. 338
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml
  47. 440
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
  48. 113
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs
  49. 29
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml
  50. 74
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml.cs
  51. 363
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinControlsDictionary.xaml
  52. 240
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml
  53. 384
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs
  54. 184
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinLayer.cs
  55. 117
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs
  56. 53
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/VirtualizingIEnumerable.cs
  57. 125
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs
  58. 144
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs
  59. 25
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs
  60. 462
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs
  61. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs
  62. 158
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs
  63. 32
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs
  64. 33
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs
  65. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs
  66. 31
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs
  67. 39
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/SharpTreeNodeAdapter.cs
  68. 67
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
  69. 185
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs
  70. 10
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/Utils.cs
  71. 478
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs
  72. 10
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs
  73. 13
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs
  74. 4
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs
  75. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs
  76. 11
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs
  77. 12
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs
  78. 13
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs
  79. 16
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs
  80. 0
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IVisualizerCommand.cs
  81. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/ObjectProperty.cs
  82. 16
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs
  83. 28
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/GraphExpression.cs
  84. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/PositionedNodeProperty.cs
  85. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentNode.cs
  86. 6
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs
  87. 86
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs
  88. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphNode.cs
  89. 4
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphProperty.cs
  90. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphControl.xaml
  91. 26
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphControl.xaml.cs
  92. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphWindow.xaml.cs
  93. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml
  94. 198
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs
  95. 85
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs
  96. 50
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs
  97. 42
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs
  98. 59
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs
  99. 12
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs
  100. 48
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs
  101. Some files were not shown because too many files have changed in this diff Show More

2
SharpDevelop.Tests.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.3.0.8807-alpha
# SharpDevelop 4.2.0.8717-Beta 2
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject
EndProjectSection

7
src/AddIns/Analysis/UnitTesting/Test/Utils/MockDebugger.cs

@ -154,12 +154,7 @@ namespace UnitTesting.Tests.Utils @@ -154,12 +154,7 @@ namespace UnitTesting.Tests.Utils
throw new NotImplementedException();
}
public bool CanSetInstructionPointer(string filename, int line, int column)
{
throw new NotImplementedException();
}
public bool SetInstructionPointer(string filename, int line, int column)
public bool SetInstructionPointer(string filename, int line, int column, bool dryRun)
{
throw new NotImplementedException();
}

7
src/AddIns/BackendBindings/Scripting/Test/Utils/MockDebugger.cs

@ -128,12 +128,7 @@ namespace ICSharpCode.Scripting.Tests.Utils @@ -128,12 +128,7 @@ namespace ICSharpCode.Scripting.Tests.Utils
throw new NotImplementedException();
}
public bool CanSetInstructionPointer(string filename, int line, int column)
{
throw new NotImplementedException();
}
public bool SetInstructionPointer(string filename, int line, int column)
public bool SetInstructionPointer(string filename, int line, int column, bool dryRun)
{
throw new NotImplementedException();
}

72
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -15,13 +15,6 @@ @@ -15,13 +15,6 @@
</Import>
<Import assembly="Debugger.Core.dll"/>
</Runtime>
<Path name="/SharpDevelop/Workbench/LanguageBindings">
<LanguageBinding
id="Pin"
class="Debugger.AddIn.Tooltips.PinningBinding"
extensions="" />
</Path>
<Path name="/SharpDevelop/Services/DebuggerService/Debugger">
<Debugger id="DefaultDebugger"
@ -96,11 +89,11 @@ @@ -96,11 +89,11 @@
class = "ICSharpCode.SharpDevelop.Gui.Pads.LoadedModulesPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "RunningThreadsPad"
<Pad id = "ThreadsPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.Threads}"
icon = "PadIcons.Threads"
class = "ICSharpCode.SharpDevelop.Gui.Pads.RunningThreadsPad"
class = "ICSharpCode.SharpDevelop.Gui.Pads.ThreadsPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "LocalVarPad"
@ -117,26 +110,12 @@ @@ -117,26 +110,12 @@
class = "ICSharpCode.SharpDevelop.Gui.Pads.ConsolePad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "MemoryPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.MemoryPad}"
icon = "MemoryPad.Icon"
class = "ICSharpCode.SharpDevelop.Gui.Pads.MemoryPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "WatchPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.Watch}"
icon = "PadIcons.LocalVariables"
class = "ICSharpCode.SharpDevelop.Gui.Pads.WatchPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "ObjectGraphPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.ObjectGraph}"
icon = "PadIcons.LocalVariables"
class = "ICSharpCode.SharpDevelop.Gui.Pads.ObjectGraphPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "ParallelStacksPad"
category = "Debugger"
@ -150,15 +129,6 @@ @@ -150,15 +129,6 @@
<MenuItem id="AddWatch" label="${res:MainWindow.Windows.Debug.Watch.AddWatch}" class="Debugger.AddIn.AddWatchCommand" />
<MenuItem id="RemoveWatch" label="${res:MainWindow.Windows.Debug.Watch.RemoveWatch}" class="Debugger.AddIn.RemoveWatchCommand" />
<MenuItem id="ClearWatches" label="${res:MainWindow.Windows.Debug.Watch.RemoveAll}" class="Debugger.AddIn.ClearWatchesCommand" />
<Condition name = "IsProcessRunning" isdebugging="True">
<Condition name = "IsProcessRunning" isdebugging="True" isprocessrunning="False">
<MenuItem id="Separator1" type="Separator" />
<MenuItem id="RefreshWatches" label="${res:MainWindow.Windows.Debug.Watch.Refresh}" class="Debugger.AddIn.RefreshWatchesCommand" />
</Condition>
</Condition>
<MenuItem id="Separator2" type="Separator" />
<MenuItem id="CopyToClipboard" label="${res:MainWindow.Windows.Debug.LocalVariables.CopyToClipboard}" class="Debugger.AddIn.CopyToClipboardCommand"/>
</Path>
<Path name = "/SharpDevelop/Dialogs/OptionsDialog">
@ -198,44 +168,6 @@ @@ -198,44 +168,6 @@
/>
</Path>
<Path name="/SharpDevelop/Pads/MemoryPad/ToolBar">
<ToolbarItem id="PreviousAddressLabel"
type="Item"
icon="MemoryPad.PreviousMemoryIcon"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.PreviousAddress}"
class="ICSharpCode.SharpDevelop.Gui.Pads.PreviousAddressCommand"/>
<ToolbarItem id="NextAddressLabel"
type="Item"
icon="MemoryPad.NextMemoryIcon"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.NextAddress}"
class="ICSharpCode.SharpDevelop.Gui.Pads.NextAddressCommand"/>
<ToolbarItem id="Separator1"
type="Separator"/>
<ToolbarItem id="JumpToAddressLabel"
type="Item"
label="${res:MainWindow.Windows.Debug.MemoryPad.JumpTo}"
class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="JumpToAddressCombo"
type="ComboBox"
class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="Separator2"
type="Separator"/>
<ToolbarItem id="RefreshMemory"
type="Item"
icon="Icons.16x16.Refresh"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.Refresh}"
class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshAddressCommand"/>
<ToolbarItem id="Separator3"
type="Separator"/>
<ToolbarItem id="ByteSizeLabel"
type="Item"
label="${res:MainWindow.Windows.Debug.MemoryPad.ByteSize}"
class="ICSharpCode.SharpDevelop.Gui.Pads.DisplayByteSizeCommand"/>
<ToolbarItem id="ByteSizeCombo"
type="ComboBox"
class="ICSharpCode.SharpDevelop.Gui.Pads.DisplayByteSizeCommand"/>
</Path>
<Path name="/SharpDevelop/Services/DebuggerService/Visualizers">
<Class class="Debugger.AddIn.Visualizers.TextVisualizerDescriptor" />
<Class class="Debugger.AddIn.Visualizers.XmlVisualizerDescriptor" />

76
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -97,30 +97,19 @@ @@ -97,30 +97,19 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="NRefactory\ExpressionEvaluator.cs" />
<Compile Include="NRefactory\ExpressionExtensionMethods.cs" />
<Compile Include="Options\DebuggingOptionsPanel.xaml.cs">
<DependentUpon>DebuggingOptionsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Pads\CallStackPad.xaml.cs">
<DependentUpon>CallStackPad.xaml</DependentUpon>
<Compile Include="Pads\CallStackPad.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Pads\Commands\MemoryPadCommands.cs" />
<Compile Include="Pads\Commands\ParallelStacksViewCommands.cs" />
<Compile Include="Pads\Commands\SelectLanguageCommand.cs" />
<Compile Include="Pads\Commands\WatchPadCommands.cs" />
<Compile Include="Pads\Controls\TreeNodeWrapper.cs" />
<Compile Include="Pads\Controls\ConditionCell.xaml.cs">
<DependentUpon>ConditionCell.xaml</DependentUpon>
</Compile>
<Compile Include="Pads\Controls\Converters.cs" />
<Compile Include="Pads\Controls\WatchList.xaml.cs">
<DependentUpon>WatchList.xaml</DependentUpon>
</Compile>
<Compile Include="Pads\Controls\WatchListAutoCompleteCell.cs">
<DependentUpon>WatchListAutoCompleteCell.xaml</DependentUpon>
</Compile>
<Compile Include="Pads\MemoryPad.cs" />
<Compile Include="Pads\Common\AutoCompleteTextBox.cs" />
<Compile Include="Pads\ParallelPad\DrawSurface.xaml.cs">
<DependentUpon>DrawSurface.xaml</DependentUpon>
<SubType>Code</SubType>
@ -133,10 +122,6 @@ @@ -133,10 +122,6 @@
<DependentUpon>ThreadStack.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Pads\WatchInputBox.xaml.cs">
<DependentUpon>WatchInputBox.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="BreakpointChangeMenuBuilder.cs" />
<Compile Include="DisableBreakpointMenuCommand.cs" />
@ -150,18 +135,16 @@ @@ -150,18 +135,16 @@
<Compile Include="Options\DebuggingSymbolsPanel.Designer.cs">
<DependentUpon>DebuggingSymbolsPanel.cs</DependentUpon>
</Compile>
<Compile Include="Pads\ObjectGraphPad.cs" />
<Compile Include="Pads\BreakPointsPad.cs" />
<Compile Include="Pads\ConsolePad.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Pads\LoadedModulesPad.cs" />
<Compile Include="Pads\LocalVarPad.cs" />
<Compile Include="Pads\RunningThreadsPad.cs" />
<Compile Include="Pads\ThreadsPad.cs" />
<Compile Include="Pads\WatchPad.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Pads\WatchPadModel.cs" />
<Compile Include="Service\AttachToProcessForm.cs">
<SubType>Form</SubType>
</Compile>
@ -175,28 +158,13 @@ @@ -175,28 +158,13 @@
<DependentUpon>EditBreakpointScriptWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Tooltips\DebuggerPopup.cs" />
<Compile Include="Tooltips\DebuggerTooltipControl.xaml.cs">
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\LazyItemsControl.cs" />
<Compile Include="Tooltips\PinCloseControl.xaml.cs">
<DependentUpon>PinCloseControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\PinDebuggerControl.xaml.cs">
<DependentUpon>PinDebuggerControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\PinLayer.cs" />
<Compile Include="Tooltips\PinningBinding.cs" />
<Compile Include="Tooltips\VirtualizingIEnumerable.cs" />
<Compile Include="Tooltips\VisualizerPicker.cs">
<DependentUpon>VisualizerPicker.xaml</DependentUpon>
</Compile>
<Compile Include="TreeModel\DebuggerResourceService.cs" />
<Compile Include="TreeModel\ICorDebug.cs" />
<Compile Include="TreeModel\IEnumerableNode.cs" />
<Compile Include="TreeModel\IListNode.cs" />
<Compile Include="TreeModel\SavedTreeNode.cs" />
<Compile Include="TreeModel\SharpTreeNodeAdapter.cs" />
<Compile Include="TreeModel\TreeNode.cs" />
<Compile Include="Visualizers\Commands\ExpressionVisualizerCommand.cs" />
<Compile Include="Visualizers\Commands\GridVisualizerCommand.cs" />
@ -209,7 +177,7 @@ @@ -209,7 +177,7 @@
<Compile Include="Visualizers\Commands\XmlVisualizerCommand.cs" />
<Compile Include="Visualizers\Common\DebuggerVisualizerException.cs" />
<Compile Include="Visualizers\Common\IEvaluate.cs" />
<Compile Include="Visualizers\Common\IListValuesProvider.cs" />
<Compile Include="Visualizers\Common\IVisualizerCommand.cs" />
<Compile Include="Visualizers\Common\ObjectProperty.cs" />
<Compile Include="Visualizers\Common\ObjectPropertyComparer.cs" />
<Compile Include="Visualizers\Common\VirtualizingCollection.cs" />
@ -223,6 +191,7 @@ @@ -223,6 +191,7 @@
<Compile Include="Visualizers\Graph\ExpandedPaths\ExpandedContentNodes.cs" />
<Compile Include="Visualizers\Graph\ExpandedPaths\ExpandedExpressions.cs" />
<Compile Include="Visualizers\Graph\ExpandedPaths\ExpandedPaths.cs" />
<Compile Include="Visualizers\Graph\GraphExpression.cs" />
<Compile Include="Visualizers\Graph\Layout\GraphEdgeRouter.cs" />
<Compile Include="Visualizers\Graph\Layout\SplineRouting\Box.cs" />
<Compile Include="Visualizers\Graph\Layout\SplineRouting\Edge.cs" />
@ -253,12 +222,10 @@ @@ -253,12 +222,10 @@
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\ThisNode.cs" />
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\NonPublicMembersNode.cs" />
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\PropertyNode.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\GridValuesProvider.cs" />
<Compile Include="Visualizers\PresentationBindings\DragScrollViewer.cs" />
<Compile Include="Visualizers\PresentationBindings\GridViewColumnHider.cs" />
<Compile Include="Visualizers\PresentationBindings\GridViewHideableColumn.cs" />
<Compile Include="Visualizers\PresentationBindings\TooltipVisibilityConverter.cs" />
<Compile Include="Visualizers\TextVisualizer\TextVisualizerMode.cs" />
<Compile Include="Visualizers\TextVisualizer\TextVisualizerWindow.xaml.cs">
<DependentUpon>TextVisualizerWindow.xaml</DependentUpon>
<SubType>Code</SubType>
@ -274,7 +241,6 @@ @@ -274,7 +241,6 @@
<EmbeddedResource Include="Service\DebuggeeExceptionForm.resx">
<DependentUpon>DebuggeeExceptionForm.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="Service\RemotingConfigurationHelpper.cs" />
<Compile Include="Service\RunToCursorCommand.cs" />
<Compile Include="Service\WindowsDebugger.cs" />
<EmbeddedResource Include="Options\DebuggingSymbolsPanel.resx">
@ -284,14 +250,7 @@ @@ -284,14 +250,7 @@
<Compile Include="..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Pads\DebuggerPad.cs" />
<Compile Include="Pads\RunningThreadsPad.Menu.cs" />
<Compile Include="TreeModel\ArrayRangeNode.cs" />
<Compile Include="TreeModel\ExpressionNode.cs" />
<Compile Include="TreeModel\IContextMenu.cs" />
<Compile Include="TreeModel\ISetText.cs" />
<Compile Include="TreeModel\ChildNodesOfObject.cs" />
<Compile Include="TreeModel\StackFrameNode.cs" />
<Compile Include="TreeModel\ValueNode.cs" />
<Compile Include="TreeModel\Utils.cs" />
<Compile Include="Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" />
<Compile Include="Visualizers\Graph\Drawing\GraphDrawer.cs" />
@ -312,9 +271,6 @@ @@ -312,9 +271,6 @@
<DependentUpon>GridVisualizerWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Visualizers\GridVisualizer\ObjectValue.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\EnumerableValuesProvider.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\ListValuesProvider.cs" />
<Compile Include="Visualizers\Utils\DebuggerHelpers.cs" />
<Compile Include="Visualizers\Utils\DictionaryExtensions.cs" />
<Compile Include="Visualizers\Utils\Lookup.cs" />
@ -324,7 +280,6 @@ @@ -324,7 +280,6 @@
</Compile>
<Compile Include="Visualizers\PresentationBindings\DisplayAttribute.cs" />
<Compile Include="Visualizers\PresentationBindings\EnumViewModel.cs" />
<None Include="COPYING" />
</ItemGroup>
<ItemGroup>
<Content Include="Debugger.AddIn.addin">
@ -379,18 +334,11 @@ @@ -379,18 +334,11 @@
</ItemGroup>
<ItemGroup>
<Page Include="Options\DebuggingOptionsPanel.xaml" />
<Page Include="Pads\CallStackPad.xaml" />
<Page Include="Pads\Controls\ConditionCell.xaml" />
<Page Include="Pads\Controls\WatchList.xaml" />
<Page Include="Pads\Controls\WatchListAutoCompleteCell.xaml" />
<Page Include="Pads\Common\CommonResources.xaml" />
<Page Include="Pads\ParallelPad\DrawSurface.xaml" />
<Page Include="Pads\ParallelPad\ThreadStack.xaml" />
<Page Include="Pads\WatchInputBox.xaml" />
<Page Include="Service\EditBreakpointScriptWindow.xaml" />
<Page Include="Tooltips\DebuggerTooltipControl.xaml" />
<Page Include="Tooltips\PinCloseControl.xaml" />
<Page Include="Tooltips\PinControlsDictionary.xaml" />
<Page Include="Tooltips\PinDebuggerControl.xaml" />
<Page Include="Tooltips\VisualizerPicker.xaml" />
<Page Include="Visualizers\Graph\Drawing\NodeControlResources.xaml" />
<Page Include="Visualizers\Graph\Drawing\PositionedGraphNodeControl.xaml" />
@ -408,8 +356,9 @@ @@ -408,8 +356,9 @@
<Name>ICSharpCode.Core.WinForms</Name>
<Private>False</Private>
</ProjectReference>
<Folder Include="NRefactory" />
<Folder Include="Pads\Commands" />
<Folder Include="Pads\Controls" />
<Folder Include="Pads\Common" />
<Folder Include="Pads\ParallelPad" />
<Folder Include="Tooltips" />
<Folder Include="Visualizers\Graph" />
@ -423,7 +372,6 @@ @@ -423,7 +372,6 @@
<Folder Include="Visualizers\Graph\ExpandedPaths" />
<Folder Include="Visualizers\Graph\ObjectGraph\TreeModel" />
<Folder Include="Visualizers\Graph\ObjectGraph" />
<Folder Include="Visualizers\GridVisualizer\ValueProviders" />
<Folder Include="Visualizers\Common" />
<Folder Include="Visualizers\Commands" />
<Folder Include="Visualizers\TextVisualizer" />

92
src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs → src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs

@ -6,17 +6,17 @@ using System.Collections; @@ -6,17 +6,17 @@ using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Debugger;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.NRefactory.Visitors
{
public class EvaluateException: GetValueException
{
public EvaluateException(INode code, string msg):base(code, msg) {}
public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(code, string.Format(msgFmt, msgArgs)) {}
public EvaluateException(INode code, string msg):base(msg) {}
public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(string.Format(msgFmt, msgArgs)) {}
}
class TypedValue
@ -51,6 +51,10 @@ namespace ICSharpCode.NRefactory.Visitors @@ -51,6 +51,10 @@ namespace ICSharpCode.NRefactory.Visitors
get { return context; }
}
public Thread EvalThread {
get { return this.Context.Thread; }
}
ExpressionEvaluator(StackFrame context)
{
this.context = context;
@ -76,19 +80,12 @@ namespace ICSharpCode.NRefactory.Visitors @@ -76,19 +80,12 @@ namespace ICSharpCode.NRefactory.Visitors
return Evaluate(Parse(code, language), context, data);
}
public static Value Evaluate(INode code, Process context)
{
if (context.SelectedStackFrame == null && context.SelectedThread.MostRecentStackFrame == null)
// This can happen when needed 'dll' is missing. This causes an exception dialog to be shown even before the applicaiton starts
throw new GetValueException("Can not evaluate because the process has no managed stack frames");
return Evaluate(code, context.GetCurrentExecutingFrame());
}
public static Value Evaluate(INode code, StackFrame context, object data = null)
{
if (context == null) throw new ArgumentNullException("context");
if (context.IsInvalid) throw new DebuggerException("The context is no longer valid");
if (context == null)
throw new GetValueException("Invalid stackframe");
if (context.IsInvalid)
throw new DebuggerException("The context is no longer valid");
TypedValue val = new ExpressionEvaluator(context).Evaluate(code, false, data);
if (val == null)
@ -113,7 +110,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -113,7 +110,7 @@ namespace ICSharpCode.NRefactory.Visitors
return astExpression;
}
public static string FormatValue(Value val)
public static string FormatValue(Thread evalThread, Value val)
{
if (val == null) {
return null;
@ -127,7 +124,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -127,7 +124,7 @@ namespace ICSharpCode.NRefactory.Visitors
foreach(Value item in val.GetArrayElements()) {
if (!first) sb.Append(", ");
first = false;
sb.Append(FormatValue(item));
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
@ -135,13 +132,13 @@ namespace ICSharpCode.NRefactory.Visitors @@ -135,13 +132,13 @@ namespace ICSharpCode.NRefactory.Visitors
StringBuilder sb = new StringBuilder();
sb.Append(val.Type.Name);
sb.Append(" {");
val = val.GetPermanentReference();
int count = (int)val.GetMemberValue("Count").PrimitiveValue;
val = val.GetPermanentReference(evalThread);
int count = (int)val.GetMemberValue(evalThread, "Count").PrimitiveValue;
for(int i = 0; i < count; i++) {
if (i > 0) sb.Append(", ");
DebugPropertyInfo itemProperty = (DebugPropertyInfo)val.Type.GetProperty("Item");
Value item = val.GetPropertyValue(itemProperty, Eval.CreateValue(val.AppDomain, i));
sb.Append(FormatValue(item));
Value item = val.GetPropertyValue(evalThread, itemProperty, Eval.CreateValue(evalThread, i));
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
@ -152,7 +149,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -152,7 +149,7 @@ namespace ICSharpCode.NRefactory.Visitors
} else if (val.Type.IsPrimitive) {
return val.PrimitiveValue.ToString();
} else {
return val.InvokeToString();
return val.InvokeToString(evalThread);
}
}
@ -163,25 +160,16 @@ namespace ICSharpCode.NRefactory.Visitors @@ -163,25 +160,16 @@ namespace ICSharpCode.NRefactory.Visitors
TypedValue Evaluate(INode expression, bool permRef, object data = null)
{
// Try to get the value from cache
// (the cache is cleared when the process is resumed)
TypedValue val;
if (context.Process.ExpressionsCache.TryGetValue(expression, out val)) {
if (val == null || !val.Value.IsInvalid)
return val;
}
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
try {
val = (TypedValue)expression.AcceptVisitor(this, data);
if (val != null && permRef)
val = new TypedValue(val.Value.GetPermanentReference(), val.Type);
} catch (GetValueException e) {
e.Expression = expression;
throw;
val = new TypedValue(val.Value.GetPermanentReference(this.EvalThread), val.Type);
} catch (NotImplementedException e) {
throw new GetValueException(expression, "Language feature not implemented: " + e.Message);
throw new EvaluateException(expression, "Language feature not implemented: " + e.Message);
} finally {
watch.Stop();
context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds);
@ -190,9 +178,6 @@ namespace ICSharpCode.NRefactory.Visitors @@ -190,9 +178,6 @@ namespace ICSharpCode.NRefactory.Visitors
if (val != null && val.Value.IsInvalid)
throw new DebuggerException("Expression \"" + expression.PrettyPrint() + "\" is invalid right after evaluation");
// Add the result to cache
context.Process.ExpressionsCache[expression] = val;
return val;
}
@ -266,7 +251,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -266,7 +251,7 @@ namespace ICSharpCode.NRefactory.Visitors
TypedValue CreateValue(object primitiveValue)
{
Value val = Eval.CreateValue(context.AppDomain, primitiveValue);
Value val = Eval.CreateValue(this.EvalThread, primitiveValue);
return new TypedValue(val, val.Type);
}
@ -312,7 +297,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -312,7 +297,7 @@ namespace ICSharpCode.NRefactory.Visitors
if (!left.Value.IsReference && left.Type.FullName != right.Type.FullName) {
throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName));
}
left.Value.SetValue(right.Value);
left.Value.SetValue(this.EvalThread, right.Value);
return right;
}
@ -367,17 +352,6 @@ namespace ICSharpCode.NRefactory.Visitors @@ -367,17 +352,6 @@ namespace ICSharpCode.NRefactory.Visitors
{
string identifier = identifierExpression.Identifier;
if (identifier == "__exception") {
if (context.Thread.CurrentException != null) {
return new TypedValue(
context.Thread.CurrentException.Value,
DebugType.CreateFromType(context.AppDomain.Mscorlib, typeof(System.Exception))
);
} else {
throw new GetValueException("No current exception");
}
}
DebugParameterInfo par = context.MethodInfo.GetParameter(identifier);
if (par != null)
return new TypedValue(par.GetValue(context), (DebugType)par.ParameterType);
@ -400,14 +374,14 @@ namespace ICSharpCode.NRefactory.Visitors @@ -400,14 +374,14 @@ namespace ICSharpCode.NRefactory.Visitors
if (thisValue != null) {
IDebugMemberInfo instMember = (IDebugMemberInfo)thisValue.Type.GetMember<MemberInfo>(identifier, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, DebugType.IsFieldOrNonIndexedProperty);
if (instMember != null)
return new TypedValue(Value.GetMemberValue(thisValue.Value, (MemberInfo)instMember), instMember.MemberType);
return new TypedValue(Value.GetMemberValue(this.EvalThread, thisValue.Value, (MemberInfo)instMember), instMember.MemberType);
}
// Static class members
foreach(DebugType declaringType in ((DebugType)context.MethodInfo.DeclaringType).GetSelfAndDeclaringTypes()) {
IDebugMemberInfo statMember = (IDebugMemberInfo)declaringType.GetMember<MemberInfo>(identifier, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, DebugType.IsFieldOrNonIndexedProperty);
if (statMember != null)
return new TypedValue(Value.GetMemberValue(null, (MemberInfo)statMember), statMember.MemberType);
return new TypedValue(Value.GetMemberValue(this.EvalThread, null, (MemberInfo)statMember), statMember.MemberType);
}
throw new GetValueException("Identifier \"" + identifier + "\" not found in this context");
@ -441,7 +415,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -441,7 +415,7 @@ namespace ICSharpCode.NRefactory.Visitors
if (pi == null)
throw new GetValueException("The object does not have an indexer property");
return new TypedValue(
target.Value.GetPropertyValue(pi, GetValues(indexes)),
target.Value.GetPropertyValue(this.EvalThread, pi, GetValues(indexes)),
(DebugType)pi.PropertyType
);
}
@ -479,7 +453,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -479,7 +453,7 @@ namespace ICSharpCode.NRefactory.Visitors
MethodInfo method = targetType.GetMethod(methodName, DebugType.BindingFlagsAllInScope, null, GetTypes(args), null);
if (method == null)
throw new GetValueException("Method " + methodName + " not found");
Value retVal = Value.InvokeMethod(target != null ? target.Value : null, method, GetValues(args));
Value retVal = Value.InvokeMethod(this.EvalThread, target != null ? target.Value : null, method, GetValues(args));
if (retVal == null)
return null;
return new TypedValue(retVal, (DebugType)method.ReturnType);
@ -492,10 +466,10 @@ namespace ICSharpCode.NRefactory.Visitors @@ -492,10 +466,10 @@ namespace ICSharpCode.NRefactory.Visitors
DebugType type = objectCreateExpression.CreateType.ResolveType(context.AppDomain);
List<TypedValue> ctorArgs = EvaluateAll(objectCreateExpression.Parameters);
ConstructorInfo ctor = type.GetConstructor(BindingFlags.Default, null, CallingConventions.Any, GetTypes(ctorArgs), null);
DebugConstructorInfo ctor = (DebugConstructorInfo)type.GetConstructor(BindingFlags.Default, null, CallingConventions.Any, GetTypes(ctorArgs), null);
if (ctor == null)
throw new EvaluateException(objectCreateExpression, "Constructor not found");
Value val = (Value)ctor.Invoke(GetValues(ctorArgs));
Value val = Value.InvokeMethod(this.EvalThread, null, ctor.MethodInfo, GetValues(ctorArgs));
return new TypedValue(val, type);
}
@ -511,14 +485,14 @@ namespace ICSharpCode.NRefactory.Visitors @@ -511,14 +485,14 @@ namespace ICSharpCode.NRefactory.Visitors
} else if (!arrayCreateExpression.ArrayInitializer.IsNull) {
length = arrayCreateExpression.ArrayInitializer.CreateExpressions.Count;
}
Value array = Eval.NewArray((DebugType)type.GetElementType(), (uint)length, null);
Value array = Eval.NewArray(this.EvalThread, (DebugType)type.GetElementType(), (uint)length, null);
if (!arrayCreateExpression.ArrayInitializer.IsNull) {
List<Expression> inits = arrayCreateExpression.ArrayInitializer.CreateExpressions;
if (inits.Count != length)
throw new EvaluateException(arrayCreateExpression, "Incorrect initializer length");
for(int i = 0; i < length; i++) {
TypedValue init = EvaluateAs(inits[i], (DebugType)type.GetElementType());
array.SetArrayElement(new int[] { i }, init.Value);
array.SetArrayElement(this.EvalThread, new int[] { i }, init.Value);
}
}
return new TypedValue(array, type);
@ -545,7 +519,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -545,7 +519,7 @@ namespace ICSharpCode.NRefactory.Visitors
if (memberInfos.Length == 0)
throw new GetValueException("Member \"" + memberReferenceExpression.MemberName + "\" not found");
return new TypedValue(
Value.GetMemberValue(target != null ? target.Value : null, memberInfos[0]),
Value.GetMemberValue(this.EvalThread, target != null ? target.Value : null, memberInfos[0]),
((IDebugMemberInfo)memberInfos[0]).MemberType
);
}
@ -772,8 +746,8 @@ namespace ICSharpCode.NRefactory.Visitors @@ -772,8 +746,8 @@ namespace ICSharpCode.NRefactory.Visitors
if (op == BinaryOperatorType.Add) {
if (left.Type.Is<string>() || right.Type.Is<string>()) {
string a = left.Value.IsNull ? string.Empty : left.Value.InvokeToString();
string b = right.Value.IsNull ? string.Empty : right.Value.InvokeToString();
string a = left.Value.IsNull ? string.Empty : left.Value.InvokeToString(this.EvalThread);
string b = right.Value.IsNull ? string.Empty : right.Value.InvokeToString(this.EvalThread);
return CreateValue(a + b);
}
}

7
src/AddIns/Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs → src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs

@ -4,20 +4,21 @@ @@ -4,20 +4,21 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Debugger;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.PrettyPrinter;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.NRefactory.Ast
{
public static class ExpressionExtensionMethods
{
public static Value Evaluate(this Expression expression, Process process)
// EXPR-EVAL (To be removed when ExpressionEvaluator is deprecated)
public static Value Evaluate(this Expression expression)
{
return ExpressionEvaluator.Evaluate(expression, process);
return ExpressionEvaluator.Evaluate(expression, WindowsDebugger.CurrentStackFrame);
}
static M SetStaticType<M>(this M expr, DebugType type) where M: INode

5
src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs

@ -4,13 +4,13 @@ @@ -4,13 +4,13 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Xml.Serialization;
using Debugger;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Services
{
public enum ShowIntegersAs { Auto, Decimal, Hexadecimal };
public enum ShowIntegersAs { Decimal, Hexadecimal, Both, Auto };
[Serializable]
public class DebuggingOptions: Options
@ -28,7 +28,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -28,7 +28,6 @@ namespace ICSharpCode.SharpDevelop.Services
DebuggeeExceptionWindowState = FormWindowState.Normal;
}
public bool ICorDebugVisualizerEnabled { get; set; }
public ShowIntegersAs ShowIntegersAs { get; set; }
public bool ShowArgumentNames { get; set; }
public bool ShowArgumentValues { get; set; }

68
src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs

@ -17,51 +17,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -17,51 +17,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class BreakPointsPad : BookmarkPadBase
{
WindowsDebugger debugger;
NDebugger debuggerCore;
public BreakPointsPad()
{
InitializeComponents();
var res = new CommonResources();
res.InitializeComponent();
myPanel.Children.Add(CreateToolBar());
Grid grid = (Grid)this.Control;
ToolBar toolbar = ToolBarService.CreateToolBar(grid, this, "/SharpDevelop/Pads/BreakpointPad/Toolbar");
grid.Children.Add(toolbar);
CreateColumns();
}
void InitializeComponents()
{
debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
if (debugger.ServiceInitialized) {
InitializeDebugger();
} else {
debugger.Initialize += delegate {
InitializeDebugger();
};
}
}
public void InitializeDebugger()
{
debuggerCore = debugger.DebuggerCore;
}
protected override ToolBar CreateToolBar()
{
ToolBar toolbar = ToolBarService.CreateToolBar(myPanel, this, "/SharpDevelop/Pads/BreakpointPad/Toolbar");
toolbar.SetValue(Grid.RowProperty, 0);
return toolbar;
}
protected override void CreateColumns()
{
string conditionHeader = StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.ConditionalColumnHeader}");
// HACK
DataTemplate cellTemplate = new ConditionCell().FindResource("ConditionCellTemplate") as DataTemplate;
listView.AddColumn(conditionHeader, cellTemplate);
this.control.listView.View = (GridView)res["breakpointsGridView"];
}
protected override bool ShowBookmarkInThisPad(SDBookmark mark)
@ -69,27 +34,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -69,27 +34,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
return mark.IsVisibleInBookmarkPad && mark is BreakpointBookmark;
}
protected override void OnItemActivated(object sender, EventArgs e)
protected override void OnItemActivated(SDBookmark bookmark)
{
var node = CurrentItem;
if (node == null)
return;
SDBookmark mark = node.Mark as SDBookmark;
if (mark == null)
return;
string fileName = mark.FileName;
if (mark is DecompiledBreakpointBookmark) {
if (bookmark is DecompiledBreakpointBookmark) {
// get information from breakpoint and navigate to the decompiled type
string assemblyFile, typeName;
if (DecompiledBreakpointBookmark.GetAssemblyAndType(fileName, out assemblyFile, out typeName)) {
NavigationService.NavigateTo(assemblyFile, typeName, string.Empty, mark.LineNumber, false);
if (DecompiledBreakpointBookmark.GetAssemblyAndType(bookmark.FileName, out assemblyFile, out typeName)) {
NavigationService.NavigateTo(assemblyFile, typeName, string.Empty, bookmark.LineNumber, false);
}
} else {
// jump to normal breakpoint
FileService.JumpToFilePosition(fileName, mark.LineNumber, 1);
// TODO: if other types of breakpoint bookmarks are available, one should do jumping/navigation here
base.OnItemActivated(bookmark);
}
}
}

210
src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.cs

@ -0,0 +1,210 @@ @@ -0,0 +1,210 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Debugger;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class CallStackPad : AbstractPadContent
{
ListView listView;
public override object Control {
get { return this.listView; }
}
public CallStackPad()
{
var res = new CommonResources();
res.InitializeComponent();
listView = new ListView();
listView.View = (GridView)res["callstackGridView"];
listView.MouseDoubleClick += listView_MouseDoubleClick;
listView.ContextMenu = CreateMenu();
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
ContextMenu CreateMenu()
{
MenuItem extMethodsItem = new MenuItem();
extMethodsItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowExternalMethods");
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods;
extMethodsItem.Click += delegate {
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods = !DebuggingOptions.Instance.ShowExternalMethods;
WindowsDebugger.RefreshPads();
};
MenuItem moduleItem = new MenuItem();
moduleItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowModuleNames");
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames;
moduleItem.Click += delegate {
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames = !DebuggingOptions.Instance.ShowModuleNames;
WindowsDebugger.RefreshPads();
};
MenuItem argNamesItem = new MenuItem();
argNamesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentNames");
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames;
argNamesItem.Click += delegate {
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames = !DebuggingOptions.Instance.ShowArgumentNames;
WindowsDebugger.RefreshPads();
};
MenuItem argValuesItem = new MenuItem();
argValuesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentValues");
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues;
argValuesItem.Click += delegate {
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues = !DebuggingOptions.Instance.ShowArgumentValues;
WindowsDebugger.RefreshPads();
};
MenuItem lineItem = new MenuItem();
lineItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowLineNumber");
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers;
lineItem.Click += delegate {
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers = !DebuggingOptions.Instance.ShowLineNumbers;
WindowsDebugger.RefreshPads();
};
return new ContextMenu() {
Items = {
extMethodsItem,
new Separator(),
moduleItem,
argNamesItem,
argValuesItem,
lineItem
}
};
}
void listView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
CallStackItem item = listView.SelectedItem as CallStackItem;
if (item == null)
return;
if (item.Frame.Process.IsPaused) {
if (item.Frame != null) {
// check for options - if these options are enabled, selecting the frame should not continue
if (!item.Frame.HasSymbols && !item.Frame.Process.Options.DecompileCodeWithoutSymbols) {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWithoutSymbolsOrDecompiledCodeOptions}",
"${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");
return;
}
WindowsDebugger.CurrentStackFrame = item.Frame;
WindowsDebugger.Instance.JumpToCurrentLine();
WindowsDebugger.RefreshPads();
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");
}
}
void RefreshPad()
{
Thread thead = WindowsDebugger.CurrentThread;
if (thead == null) {
listView.ItemsSource = null;
} else {
var items = new ObservableCollection<CallStackItem>();
bool previousItemIsExternalMethod = false;
WindowsDebugger.CurrentProcess.EnqueueForEach(
listView.Dispatcher,
thead.GetCallstack(100),
f => items.AddIfNotNull(CreateItem(f, ref previousItemIsExternalMethod))
);
listView.ItemsSource = items;
}
}
CallStackItem CreateItem(StackFrame frame, ref bool previousItemIsExternalMethod)
{
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods;
if (frame.HasSymbols || showExternalMethods) {
// Show the method in the list
previousItemIsExternalMethod = false;
return new CallStackItem() {
Frame = frame,
ImageSource = new ResourceServiceImage("Icons.16x16.Method").ImageSource,
Name = GetFullName(frame)
};
} else {
// Show [External methods] in the list
if (previousItemIsExternalMethod)
return null;
previousItemIsExternalMethod = true;
return new CallStackItem() {
Name = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ExternalMethods")
};
}
}
internal static string GetFullName(StackFrame frame)
{
StringBuilder name = new StringBuilder(64);
if (DebuggingOptions.Instance.ShowModuleNames) {
name.Append(frame.MethodInfo.DebugModule.ToString());
name.Append('!');
}
name.Append(frame.MethodInfo.DeclaringType.FullName);
name.Append('.');
name.Append(frame.MethodInfo.Name);
if (DebuggingOptions.Instance.ShowArgumentNames || DebuggingOptions.Instance.ShowArgumentValues) {
name.Append('(');
for (int i = 0; i < frame.ArgumentCount; i++) {
if (DebuggingOptions.Instance.ShowArgumentNames) {
name.Append(frame.MethodInfo.GetParameters()[i].Name);
if (DebuggingOptions.Instance.ShowArgumentValues) {
name.Append('=');
}
}
if (DebuggingOptions.Instance.ShowArgumentValues) {
try {
name.Append(frame.GetArgumentValue(i).AsString(100));
} catch (GetValueException) {
name.Append(ResourceService.GetString("Global.NA"));
}
}
if (i < frame.ArgumentCount - 1) {
name.Append(", ");
}
}
name.Append(')');
}
if (DebuggingOptions.Instance.ShowLineNumbers) {
if (frame.NextStatement != null) {
name.Append(':');
name.Append(frame.NextStatement.StartLine.ToString());
}
}
return name.ToString();
}
}
public class CallStackItem
{
public StackFrame Frame { get; set; }
public ImageSource ImageSource { get; set; }
public string Name { get; set; }
public Brush FontColor {
get { return this.Frame == null || this.Frame.HasSymbols ? Brushes.Black : Brushes.Gray; }
}
}
}

41
src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml

@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
<UserControl x:Class="ICSharpCode.SharpDevelop.Gui.Pads.CallStackPadContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sd="http://icsharpcode.net/sharpdevelop/core"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<ListView Name="view" MouseLeftButtonUp="View_MouseLeftButtonUp" KeyDown="View_KeyDown">
<ListView.View>
<GridView>
<GridViewColumn Header="{sd:Localize MainWindow.Windows.Debug.CallStack.Module}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ModuleName}" Foreground="{Binding FontColor}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{sd:Localize Global.Name}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Foreground="{Binding FontColor}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{sd:Localize Global.TextLine}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Line}" Foreground="{Binding FontColor}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{sd:Localize MainWindow.Windows.Debug.CallStack.Language}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Language}" Foreground="{Binding FontColor}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</UserControl>

306
src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml.cs

@ -1,306 +0,0 @@ @@ -1,306 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Debugger;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
/// <summary>
/// Interaction logic for CallStackPadContent.xaml
/// </summary>
public partial class CallStackPadContent : UserControl
{
CallStackPad callStackPad;
Process debuggedProcess;
public CallStackPadContent(CallStackPad pad)
{
this.callStackPad = pad;
InitializeComponent();
view.ContextMenu = CreateMenu();
((GridView)view.View).Columns[0].Width = DebuggingOptions.Instance.ShowModuleNames ? 100d : 0d;
((GridView)view.View).Columns[2].Width = DebuggingOptions.Instance.ShowLineNumbers ? 50d : 0d;
}
ContextMenu CreateMenu()
{
MenuItem extMethodsItem = new MenuItem();
extMethodsItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowExternalMethods");
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods;
extMethodsItem.Click += delegate {
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods = !DebuggingOptions.Instance.ShowExternalMethods;
callStackPad.InvalidatePad();
};
MenuItem moduleItem = new MenuItem();
moduleItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowModuleNames");
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames;
moduleItem.Click += delegate {
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames = !DebuggingOptions.Instance.ShowModuleNames;
((GridView)view.View).Columns[0].Width = DebuggingOptions.Instance.ShowModuleNames ? 100d : 0d;
callStackPad.InvalidatePad();
};
MenuItem argNamesItem = new MenuItem();
argNamesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentNames");
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames;
argNamesItem.Click += delegate {
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames = !DebuggingOptions.Instance.ShowArgumentNames;
callStackPad.InvalidatePad();
};
MenuItem argValuesItem = new MenuItem();
argValuesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentValues");
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues;
argValuesItem.Click += delegate {
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues = !DebuggingOptions.Instance.ShowArgumentValues;
callStackPad.InvalidatePad();
};
MenuItem lineItem = new MenuItem();
lineItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowLineNumber");
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers;
lineItem.Click += delegate {
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers = !DebuggingOptions.Instance.ShowLineNumbers;
((GridView)view.View).Columns[2].Width = DebuggingOptions.Instance.ShowLineNumbers ? 50d : 0d;
callStackPad.InvalidatePad();
};
return new ContextMenu() {
Items = {
extMethodsItem,
new Separator(),
moduleItem,
argNamesItem,
argValuesItem,
lineItem
}
};
}
public void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_Paused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_Paused;
}
callStackPad.InvalidatePad();
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
callStackPad.InvalidatePad();
}
void View_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (debuggedProcess == null)
return;
if (debuggedProcess.IsPaused) {
CallStackItem item = view.SelectedItem as CallStackItem;
if (item == null)
return;
if (item.Frame != null && debuggedProcess.SelectedThread != null) {
// check for options - if these options are enabled, selecting the frame should not continue
if (!item.Frame.HasSymbols && !debuggedProcess.Options.DecompileCodeWithoutSymbols) {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWithoutSymbolsOrDecompiledCodeOptions}",
"${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");
return;
}
debuggedProcess.SelectedThread.SelectedStackFrame = item.Frame;
debuggedProcess.PauseSession.PausedReason = PausedReason.CurrentFunctionChanged;
debuggedProcess.OnPaused(); // Force refresh of pads - artificial pause
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");
}
}
void View_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter) {
View_MouseLeftButtonUp(sender, null);
e.Handled = true;
}
}
internal void RefreshPad()
{
if (debuggedProcess == null || debuggedProcess.IsRunning || debuggedProcess.SelectedThread == null) {
view.ItemsSource = null;
return;
}
var items = new ObservableCollection<CallStackItem>();
using(new PrintTimes("Callstack refresh")) {
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods;
bool previousItemIsExternalMethod = false;
debuggedProcess.EnqueueForEach(
Dispatcher,
debuggedProcess.SelectedThread.GetCallstack(100),
f => items.AddIfNotNull(CreateItem(f, showExternalMethods, ref previousItemIsExternalMethod))
);
}
view.ItemsSource = items;
}
CallStackItem CreateItem(StackFrame frame, bool showExternalMethods, ref bool previousItemIsExternalMethod)
{
CallStackItem item;
// line number
string lineNumber = string.Empty;
if (DebuggingOptions.Instance.ShowLineNumbers) {
if (frame.NextStatement != null)
lineNumber = frame.NextStatement.StartLine.ToString();
}
// show modules names
string moduleName = string.Empty;
if (DebuggingOptions.Instance.ShowModuleNames) {
moduleName = frame.MethodInfo.DebugModule.ToString();
}
if (frame.HasSymbols || showExternalMethods) {
// Show the method in the list
item = new CallStackItem() {
Name = GetFullName(frame), Language = "", Line = lineNumber, ModuleName = moduleName
};
previousItemIsExternalMethod = false;
item.Frame = frame;
} else {
// Show [External methods] in the list
if (previousItemIsExternalMethod) return null;
item = new CallStackItem() {
Name = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ExternalMethods"),
Language = ""
};
previousItemIsExternalMethod = true;
}
return item;
}
internal static string GetFullName(StackFrame frame)
{
bool showArgumentNames = DebuggingOptions.Instance.ShowArgumentNames;
bool showArgumentValues = DebuggingOptions.Instance.ShowArgumentValues;
bool showLineNumber = DebuggingOptions.Instance.ShowLineNumbers;
bool showModuleNames = DebuggingOptions.Instance.ShowModuleNames;
StringBuilder name = new StringBuilder();
name.Append(frame.MethodInfo.DeclaringType.FullName);
name.Append('.');
name.Append(frame.MethodInfo.Name);
if (showArgumentNames || showArgumentValues) {
name.Append("(");
for (int i = 0; i < frame.ArgumentCount; i++) {
string parameterName = null;
string argValue = null;
if (showArgumentNames) {
try {
parameterName = frame.MethodInfo.GetParameters()[i].Name;
} catch { }
if (parameterName == "") parameterName = null;
}
if (showArgumentValues) {
try {
argValue = frame.GetArgumentValue(i).AsString(100);
} catch { }
}
if (parameterName != null && argValue != null) {
name.Append(parameterName);
name.Append("=");
name.Append(argValue);
}
if (parameterName != null && argValue == null) {
name.Append(parameterName);
}
if (parameterName == null && argValue != null) {
name.Append(argValue);
}
if (parameterName == null && argValue == null) {
name.Append(ResourceService.GetString("Global.NA"));
}
if (i < frame.ArgumentCount - 1) {
name.Append(", ");
}
}
name.Append(")");
}
return name.ToString();
}
}
public class CallStackItem
{
public string Name { get; set; }
public string Language { get; set; }
public StackFrame Frame { get; set; }
public string Line { get; set; }
public string ModuleName { get; set; }
public Brush FontColor {
get { return Frame == null || Frame.HasSymbols ? Brushes.Black : Brushes.Gray; }
}
}
public class CallStackPad : DebuggerPad
{
CallStackPadContent callStackList;
static CallStackPad instance;
public static CallStackPad Instance {
get { return instance; }
}
public CallStackPad()
{
instance = this;
}
public override object Control {
get {
return callStackList;
}
}
protected override void InitializeComponents()
{
callStackList = new CallStackPadContent(this);
}
protected override void SelectProcess(Process process)
{
callStackList.SelectProcess(process);
}
protected override void RefreshPad()
{
callStackList.RefreshPad();
}
}
}

127
src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs

@ -1,127 +0,0 @@ @@ -1,127 +0,0 @@
// 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.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public sealed class JumpToAddressCommand : AbstractComboBoxCommand
{
MemoryPad pad;
ComboBox comboBox;
protected override void OnOwnerChanged(EventArgs e)
{
this.pad = this.Owner as MemoryPad;
if (this.pad == null)
return;
comboBox = this.ComboBox as ComboBox;
if (this.comboBox == null)
return;
comboBox.KeyUp += (s, ea) => { if (ea.Key == Key.Enter) Run(); };
comboBox.IsEditable = true;
comboBox.Width = 130;
base.OnOwnerChanged(e);
}
public override void Run()
{
if (this.pad != null && this.comboBox != null) {
pad.JumpToAddress(comboBox.Text);
}
base.Run();
}
}
public abstract class ItemMemoryCommand : AbstractCommand
{
protected MemoryPad pad;
protected override void OnOwnerChanged(EventArgs e)
{
this.pad = this.Owner as MemoryPad;
if (this.pad == null)
return;
base.OnOwnerChanged(e);
}
}
public sealed class RefreshAddressCommand : ItemMemoryCommand
{
public override void Run()
{
if (this.pad == null)
return;
this.pad.Refresh();
}
}
public sealed class NextAddressCommand : ItemMemoryCommand
{
public override void Run()
{
if (this.pad == null)
return;
this.pad.MoveToNextAddress();
}
}
public sealed class PreviousAddressCommand : ItemMemoryCommand
{
public override void Run()
{
if (this.pad == null)
return;
this.pad.MoveToPreviousAddress();
}
}
public sealed class DisplayByteSizeCommand : AbstractComboBoxCommand
{
MemoryPad pad;
ComboBox comboBox;
protected override void OnOwnerChanged(EventArgs e)
{
this.pad = this.Owner as MemoryPad;
if (this.pad == null)
return;
comboBox = this.ComboBox as ComboBox;
if (this.comboBox == null)
return;
comboBox.SelectionChanged += (s, ea) => { Run(); };
comboBox.Items.Add(1);
comboBox.Items.Add(2);
comboBox.Items.Add(4);
comboBox.Text = "1";
comboBox.Width = 30;
comboBox.IsEditable = false;
base.OnOwnerChanged(e);
}
public override void Run()
{
if (this.pad != null && this.comboBox != null) {
pad.DisplayByteSize = Convert.ToByte(this.comboBox.SelectedValue);
pad.DisplayMemory();
}
base.Run();
}
}
}

128
src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs

@ -2,20 +2,15 @@ @@ -2,20 +2,15 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Debugger.AddIn.Pads;
using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.Core.WinForms;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn
{
@ -25,24 +20,9 @@ namespace Debugger.AddIn @@ -25,24 +20,9 @@ namespace Debugger.AddIn
{
if (this.Owner is WatchPad) {
WatchPad pad = (WatchPad)this.Owner;
var inputWindow = new WatchInputBox(StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.AddWatch}"),
StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.EnterExpression}"));
inputWindow.Owner = ICSharpCode.SharpDevelop.Gui.WorkbenchSingleton.MainWindow;
if (inputWindow.ShowDialog() != true)
return;
string input = inputWindow.CommandText;
if (!string.IsNullOrEmpty(input)) {
var text = new TextNode(null, input, inputWindow.ScriptLanguage).ToSharpTreeNode();
var list = pad.WatchList;
if(!list.WatchItems.Any(n => text.Node.FullName == ((TreeNodeWrapper)n).Node.FullName))
list.WatchItems.Add(text);
}
pad.InvalidatePad();
var node = new TreeNode(string.Empty, null).ToSharpTreeNode();
pad.Items.Add(node);
pad.Tree.FocusNode(node);
}
}
}
@ -53,24 +33,8 @@ namespace Debugger.AddIn @@ -53,24 +33,8 @@ namespace Debugger.AddIn
{
if (this.Owner is WatchPad) {
WatchPad pad = (WatchPad)this.Owner;
var list = pad.WatchList;
var node = list.SelectedNode;
if (node == null)
return;
list.WatchItems.Remove(node);
((WatchPad)this.Owner).InvalidatePad();
}
}
}
public class RefreshWatchesCommand : AbstractMenuCommand
{
public override void Run()
{
if (this.Owner is WatchPad) {
((WatchPad)this.Owner).InvalidatePad();
pad.Items.Remove(pad.Tree.SelectedItem as SharpTreeNodeAdapter);
WindowsDebugger.RefreshPads();
}
}
}
@ -81,86 +45,8 @@ namespace Debugger.AddIn @@ -81,86 +45,8 @@ namespace Debugger.AddIn
{
if (this.Owner is WatchPad) {
WatchPad pad = (WatchPad)this.Owner;
var list = pad.WatchList;
list.WatchItems.Clear();
pad.Items.Clear();
}
}
}
public class CopyToClipboardCommand : AbstractMenuCommand
{
public override void Run()
{
if (this.Owner is WatchPad) {
WatchPad pad = (WatchPad)this.Owner;
var node = pad.WatchList.SelectedNode;
if (node != null && node.Node is ExpressionNode) {
string text = ((ExpressionNode)node.Node).FullText;
ClipboardWrapper.SetText(text);
}
}
}
}
public class WatchScriptingLanguageMenuBuilder : ISubmenuBuilder, IMenuItemBuilder
{
public ToolStripItem[] BuildSubmenu(Codon codon, object owner)
{
List<ToolStripItem> items = new List<ToolStripItem>();
if (owner is WatchPad) {
WatchPad pad = (WatchPad)owner;
if (pad.WatchList.SelectedNode == null)
return items.ToArray();
var node = pad.WatchList.SelectedNode.Node;
while (node.Parent != null && node.Parent.Parent != null)
{
node = node.Parent;
}
if (!(node is TextNode))
return items.ToArray();
foreach (string item in SupportedLanguage.GetNames(typeof(SupportedLanguage))) {
items.Add(MakeItem(item, item, node as TextNode, (sender, e) => HandleItem(sender)));
}
}
return items.ToArray();
}
ToolStripMenuItem MakeItem(string title, string name, TextNode tag, EventHandler onClick)
{
ToolStripMenuItem menuItem = new ToolStripMenuItem(StringParser.Parse(title));
menuItem.Click += onClick;
menuItem.Name = name;
menuItem.Tag = tag;
if (name == tag.Language.ToString())
menuItem.Checked = true;
return menuItem;
}
void HandleItem(object sender)
{
ToolStripMenuItem item = null;
if (sender is ToolStripMenuItem)
item = (ToolStripMenuItem)sender;
if (item != null) {
TextNode node = (TextNode)item.Tag;
node.Language = (SupportedLanguage)SupportedLanguage.Parse(typeof(SupportedLanguage), item.Text);
}
}
public System.Collections.ICollection BuildItems(Codon codon, object owner)
{
return BuildSubmenu(codon, owner).TranslateToWpf();
}
}
}

120
src/AddIns/Debugger/Debugger.AddIn/Pads/Common/AutoCompleteTextBox.cs

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Pads.Controls
{
public class AutoCompleteTextBox : UserControl
{
TextEditor editor;
ITextEditor editorAdapter;
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, TextChanged));
public static readonly DependencyProperty IsEditableProperty =
DependencyProperty.Register("IsEditable", typeof(bool), typeof(AutoCompleteTextBox),
new FrameworkPropertyMetadata(true, IsEditableChanged));
public string Text {
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsEditable {
get { return (bool)GetValue(IsEditableProperty); }
set { SetValue(IsEditableProperty, value); }
}
static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((AutoCompleteTextBox)d).editor.Text = (string)e.NewValue;
}
static void IsEditableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((AutoCompleteTextBox)d).editor.IsReadOnly = !(bool)e.NewValue;
}
public AutoCompleteTextBox()
{
object tmp;
this.editorAdapter = EditorControlService.CreateEditor(out tmp);
this.editor = (TextEditor)tmp;
this.editor.Background = Brushes.Transparent;
this.editor.ShowLineNumbers = false;
this.editor.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
this.editor.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
this.editor.TextArea.GotKeyboardFocus += delegate {
this.Background = Brushes.White;
};
this.editor.TextArea.LostKeyboardFocus += delegate {
this.Background = Brushes.Transparent;
this.Text = this.editor.Text;
this.editor.Select(0, 0);
};
this.editor.TextArea.PreviewKeyDown += editor_TextArea_PreviewKeyDown;
this.editor.TextArea.TextEntered += editor_TextArea_TextEntered;
this.Content = this.editor;
}
void editor_TextArea_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return || e.Key == Key.Escape) {
if (e.Key == Key.Return)
this.Text = this.editor.Text;
e.Handled = true;
}
}
void editor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
{
StackFrame frame = WindowsDebugger.CurrentStackFrame;
if (e.Text == "." && frame != null)
ShowDotCompletion(frame, this.editor.Text);
}
private void ShowDotCompletion(StackFrame frame, string currentText)
{
string language = ProjectService.CurrentProject == null ? "C#" : ProjectService.CurrentProject.Language;
NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.GetLanguage(language));
var seg = frame.NextStatement;
var expressionFinder = ParserService.GetExpressionFinder(seg.Filename);
var info = ParserService.GetParseInformation(seg.Filename);
string text = ParserService.GetParseableFileContent(seg.Filename).Text;
int currentOffset = this.editor.CaretOffset;
var expr = expressionFinder.FindExpression(currentText, currentOffset);
expr.Region = new DomRegion(seg.StartLine, seg.StartColumn, seg.EndLine, seg.EndColumn);
var rr = resolver.Resolve(expr, info, text);
if (rr != null) {
editorAdapter.ShowCompletionWindow(new DotCodeCompletionItemProvider().GenerateCompletionListForResolveResult(rr, expr.Context));
}
}
}
}

99
src/AddIns/Debugger/Debugger.AddIn/Pads/Common/CommonResources.xaml

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
<ResourceDictionary
x:Class="CommonResources"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Debugger.AddIn.Pads.Controls"
xmlns:core="http://icsharpcode.net/sharpdevelop/core"
xmlns:tv="http://icsharpcode.net/sharpdevelop/treeview"
>
<!-- Local Variables Pad and Watch Pad -->
<tv:SharpGridView x:Key="variableGridView">
<GridView.Columns>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.LocalVariables.NameColumn}" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<tv:SharpTreeNodeView/>
<local:AutoCompleteTextBox Margin="-6 0 0 0" Text="{Binding Node.Name}" IsEditable="{Binding Node.CanSetName}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.LocalVariables.ValueColumn}" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<local:AutoCompleteTextBox Text="{Binding Node.Value}" IsEditable="{Binding Node.CanSetValue}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.LocalVariables.TypeColumn}" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<local:AutoCompleteTextBox Text="{Binding Node.Type}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</tv:SharpGridView>
<!-- Callstack -->
<GridView x:Key="callstackGridView">
<GridViewColumn Header="{core:Localize Global.Name}" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Margin="1, 1, 5, 1" />
<TextBlock Text="{Binding Name}" Foreground="{Binding FontColor}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
<!-- Breakpoints Pad -->
<GridView x:Key="breakpointsGridView">
<GridViewColumn Header="" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsEnabled, Mode=TwoWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{core:Localize MainWindow.Windows.BookmarkPad.LocationText}" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Margin="1, 1, 5, 1" />
<TextBlock Text="{Binding FileNameAndLineNumber}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Conditional.Breakpoints.ConditionalColumnHeader}" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<local:AutoCompleteTextBox Text="{Binding Condition}" MinWidth="100" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
<!-- Loaded Modules -->
<GridView x:Key="loadedModulesGridView">
<GridViewColumn Header="{core:Localize Global.Name}" Width="250" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Modules.AddressColumn}" Width="100" DisplayMemberBinding="{Binding Address}"/>
<GridViewColumn Header="{core:Localize Global.Path}" Width="250" DisplayMemberBinding="{Binding Path}"/>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Modules.OrderColumn}" Width="80" DisplayMemberBinding="{Binding Order}"/>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Modules.SymbolsColumn}" Width="130" DisplayMemberBinding="{Binding Symbols}"/>
</GridView>
<!-- Threads -->
<GridView x:Key="theadsGridView">
<GridViewColumn Header="{core:Localize Global.ID}" Width="100" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="{core:Localize Global.Name}" Width="300" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Threads.Priority}" Width="120" DisplayMemberBinding="{Binding Priority}"/>
<GridViewColumn Header="{core:Localize MainWindow.Windows.Debug.Threads.Frozen}" Width="80" DisplayMemberBinding="{Binding Frozen}"/>
</GridView>
</ResourceDictionary>

53
src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs

@ -45,34 +45,27 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -45,34 +45,27 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
string Evaluate(string code)
{
if (process == null) {
Process process = WindowsDebugger.CurrentProcess;
StackFrame frame = WindowsDebugger.CurrentStackFrame;
if (process == null)
return "No process is being debugged";
}
if (process.IsRunning) {
if (process.IsRunning)
return "The process is running";
}
if (frame == null)
return "No current execution frame";
try {
var debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
StackFrame frame = debugger.DebuggedProcess.GetCurrentExecutingFrame();
if (frame == null) return "No current execution frame";
object data = debugger.debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken,
object data = ((WindowsDebugger)DebuggerService.CurrentDebugger).debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken,
frame.MethodInfo.MetadataToken,
code);
Value val = ExpressionEvaluator.Evaluate(code, SelectedLanguage, frame, data);
return ExpressionEvaluator.FormatValue(val);
return ExpressionEvaluator.FormatValue(WindowsDebugger.EvalThread, val);
} catch (GetValueException e) {
return e.Message;
}
}
Process process;
public Process Process {
get { return process; }
set { process = value; }
}
protected override string Prompt {
get {
return "> ";
@ -102,35 +95,17 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -102,35 +95,17 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
public ConsolePad()
{
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
debugger.ProcessSelected += delegate(object sender, ProcessEventArgs e) {
this.Process = e.Process;
};
this.Process = debugger.DebuggedProcess;
}
protected override void AbstractConsolePadTextEntered(object sender, TextCompositionEventArgs e)
{
if (this.process == null || this.process.IsRunning)
return;
StackFrame frame = this.process.GetCurrentExecutingFrame();
if (frame == null)
return;
foreach (char ch in e.Text) {
if (ch == '.') {
ShowDotCompletion(console.CommandText);
}
}
StackFrame frame = WindowsDebugger.CurrentStackFrame;
if (e.Text == "." && frame != null)
ShowDotCompletion(frame, console.CommandText);
}
void ShowDotCompletion(string currentText)
void ShowDotCompletion(StackFrame frame, string currentText)
{
StackFrame frame = this.process.GetCurrentExecutingFrame();
if (frame == null)
return;
var seg = frame.NextStatement;
if (seg == null)
return;

22
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/ConditionCell.xaml

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
<UserControl x:Class="Debugger.AddIn.Pads.Controls.ConditionCell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SDGui="clr-namespace:ICSharpCode.SharpDevelop.Gui;assembly=ICSharpCode.SharpDevelop"
xmlns:local="clr-namespace:Debugger.AddIn.Pads.Controls">
<UserControl.Resources>
<DataTemplate x:Key="ConditionCellTemplate">
<Grid HorizontalAlignment="Stretch">
<local:ConditionCell
CommandText="{Binding Path=Condition, UpdateSourceTrigger=LostFocus}"
Tag="{Binding Path=Tag, Mode=TwoWay}"/>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
</Grid.ColumnDefinitions>
<ContentPresenter
Name="ConsolePanel" />
</Grid>
</UserControl>

196
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/ConditionCell.xaml.cs

@ -1,196 +0,0 @@ @@ -1,196 +0,0 @@
// 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.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.AvalonEdit;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks.Pad.Controls;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace Debugger.AddIn.Pads.Controls
{
public partial class ConditionCell : UserControl
{
private string language;
protected ConsoleControl console;
public static readonly DependencyProperty CommandTextProperty =
DependencyProperty.Register("CommandText", typeof(string), typeof(ConditionCell),
new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandTextChanged)));
private NRefactoryResolver resolver;
public ConditionCell()
{
InitializeComponent();
console = new ConsoleControl();
console.TextAreaTextEntered += new TextCompositionEventHandler(consoleControl_TextAreaTextEntered);
console.TextAreaPreviewKeyDown += new KeyEventHandler(console_TextAreaPreviewKeyDown);
console.LostFocus += new RoutedEventHandler(console_LostFocus);
console.HideScrollBar();
ConsolePanel.Content = console;
// get language
if (ProjectService.CurrentProject == null)
language = "C#";
else
language = ProjectService.CurrentProject.Language;
resolver = new NRefactoryResolver(LanguageProperties.GetLanguage(language));
// FIXME set language
if (language == "VB" || language == "VBNet") {
console.SetHighlighting("VBNET");
}
else {
console.SetHighlighting("C#");
}
}
/// <summary>
/// Gets/sets the command text displayed at the command prompt.
/// </summary>
public string CommandText {
get { return console.CommandText.Trim(); }
set { console.CommandText = value; }
}
private BreakpointBookmark Breakpoint {
get {
var model = Model;
return model.Mark as BreakpointBookmark;
}
}
private ListViewPadItemModel Model {
get { return Tag as ListViewPadItemModel; }
}
private ITextEditor TextEditor {
get {
return console.TextEditor;
}
}
private void console_TextAreaPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return || e.Key == Key.Escape) {
if (e.Key == Key.Escape)
CommandText = string.Empty;
else {
if(!CheckSyntax())
return;
}
UpdateBreakpoint();
e.Handled = true;
}
}
private void console_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(CommandText) || !this.CheckSyntax())
return;
UpdateBreakpoint();
}
private void UpdateBreakpoint()
{
Breakpoint.Condition = CommandText;
Model.Condition = CommandText;
Breakpoint.ScriptLanguage = language;
Model.Language = language;
if (!string.IsNullOrEmpty(console.CommandText)) {
Breakpoint.Action = BreakpointAction.Condition;
if (Breakpoint.IsEnabled)
Model.Image = BreakpointBookmark.BreakpointConditionalImage.ImageSource;
}
else {
Breakpoint.Action = BreakpointAction.Break;
if (Breakpoint.IsEnabled)
Model.Image = BreakpointBookmark.BreakpointImage.ImageSource;
}
}
private bool CheckSyntax()
{
string command = CommandText;
if (string.IsNullOrEmpty(command))
return true;
// FIXME workaround the NRefactory issue that needs a ; at the end
if (language == "C#") {
if(!command.EndsWith(";"))
command += ";";
// FIXME only one string should be available; highlighting expects C#, supproted language, CSharp
language = "CSharp";
}
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language.ToString(), true);
using (var parser = ParserFactory.CreateParser(supportedLanguage, new StringReader(TextEditor.Document.Text))) {
parser.ParseExpression();
if (parser.Errors.Count > 0) {
MessageService.ShowError(parser.Errors.ErrorOutput);
return false;
}
}
return true;
}
private void consoleControl_TextAreaTextEntered(object sender, TextCompositionEventArgs e)
{
foreach (char ch in e.Text) {
if (ch == '.') {
ShowDotCompletion(console.CommandText);
}
}
}
private void ShowDotCompletion(string currentText)
{
var seg = Breakpoint;
var expressionFinder = ParserService.GetExpressionFinder(seg.FileName.ToString());
var info = ParserService.GetParseInformation(seg.FileName.ToString());
string text = ParserService.GetParseableFileContent(seg.FileName.ToString()).Text;
int currentOffset = TextEditor.Caret.Offset - console.CommandOffset - 1;
var expr = expressionFinder.FindExpression(currentText, currentOffset);
expr.Region = new DomRegion(seg.LineNumber, seg.ColumnNumber, seg.LineNumber, seg.ColumnNumber);
var rr = resolver.Resolve(expr, info, text);
if (rr != null) {
TextEditor.ShowCompletionWindow(new DotCodeCompletionItemProvider().GenerateCompletionListForResolveResult(rr, expr.Context));
}
}
private static void OnCommandTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var cell = d as ConditionCell;
cell.CommandText = e.NewValue.ToString();
}
}
}

28
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/Converters.cs

@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
// 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.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace Debugger.AddIn.Pads.Controls
{
public class BoolToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
bool val = bool.Parse(parameter.ToString());
return val == (bool.Parse(values[0].ToString()) && bool.Parse(values[1].ToString())) ? Visibility.Visible : Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

82
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl x:Class="Debugger.AddIn.Pads.Controls.WatchList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Debugger.AddIn.Pads.Controls"
xmlns:core="http://icsharpcode.net/sharpdevelop/core"
xmlns:tv="http://icsharpcode.net/sharpdevelop/treeview">
<UserControl.Resources>
<local:BoolToVisibilityConverter x:Key="boolToVisibility" />
<Style x:Key="BorderStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="1,0,1,1"></Setter>
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style TargetType="{x:Type TextBox}" x:Key="TextBoxValueStyle">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Background" Value="White"/>
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource boolToVisibility}" ConverterParameter="True">
<Binding Path="Node.CanSetText" />
<Binding Path="IsSelected" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="TextBlockValueStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource boolToVisibility}" ConverterParameter="False">
<Binding Path="Node.CanSetText" />
<Binding Path="IsSelected" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
<!-- Value column -->
<DataTemplate x:Key="CellTemplate_Value">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" MinWidth="200" Text="{Binding Node.Text}" Style="{StaticResource TextBlockValueStyle}" />
<TextBox Text="{Binding Node.Text, Mode=OneWay}" Style="{StaticResource TextBoxValueStyle}" KeyUp="OnValueTextBoxKeyUp" />
</StackPanel>
</DataTemplate>
<!-- Type column -->
<DataTemplate x:Key="CellTemplate_Type">
<TextBlock VerticalAlignment="Center" MinWidth="200" Text="{Binding Node.Type}" />
</DataTemplate>
</UserControl.Resources>
<DockPanel>
<tv:SharpTreeView x:Name="myList" ShowRoot="False" PreviewMouseDoubleClick="MyListPreviewMouseDoubleClick" AllowDrop="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=AllowDrop}">
<tv:SharpTreeView.View>
<tv:SharpGridView>
<GridView.Columns>
<GridViewColumn Header="{core:Localize Global.Name}" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<tv:SharpTreeNodeView>
<tv:SharpTreeNodeView.CellEditor>
<local:WatchListAutoCompleteCell
CommandText="{Binding Node.Name, Mode=OneWay}"
CommandEntered="WatchListAutoCompleteCellCommandEntered"/>
</tv:SharpTreeNodeView.CellEditor>
</tv:SharpTreeNodeView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{core:Localize Dialog.HighlightingEditor.Properties.Value}"
CellTemplate="{StaticResource CellTemplate_Value}"
Width="200" />
<GridViewColumn Header="{core:Localize ResourceEditor.ResourceEdit.TypeColumn}"
CellTemplate="{StaticResource CellTemplate_Type}"
Width="200" />
</GridView.Columns>
</tv:SharpGridView>
</tv:SharpTreeView.View>
</tv:SharpTreeView>
</DockPanel>
</UserControl>

94
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs

@ -1,94 +0,0 @@ @@ -1,94 +0,0 @@
// 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.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.TreeView;
namespace Debugger.AddIn.Pads.Controls
{
public enum WatchListType
{
LocalVar,
Watch
}
public partial class WatchList : UserControl
{
public WatchList(WatchListType type)
{
InitializeComponent();
WatchType = type;
if (type == WatchListType.Watch)
myList.Root = new WatchRootNode();
else
myList.Root = new SharpTreeNode();
}
public WatchListType WatchType { get; private set; }
public SharpTreeNodeCollection WatchItems {
get { return myList.Root.Children; }
}
public TreeNodeWrapper SelectedNode {
get { return myList.SelectedItem as TreeNodeWrapper; }
}
void OnValueTextBoxKeyUp(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter && e.Key != Key.Escape) {
e.Handled = true;
return;
}
if (e.Key == Key.Enter) {
if(SelectedNode.Node is ExpressionNode) {
var node = (ExpressionNode)SelectedNode.Node;
node.SetText(((TextBox)sender).Text);
}
}
if (e.Key == Key.Enter || e.Key == Key.Escape) {
myList.UnselectAll();
if (LocalVarPad.Instance != null)
LocalVarPad.Instance.InvalidatePad();
if (WatchPad.Instance != null)
WatchPad.Instance.InvalidatePad();
}
}
void WatchListAutoCompleteCellCommandEntered(object sender, EventArgs e)
{
var selectedNode = SelectedNode;
if (selectedNode == null) return;
if (WatchType != WatchListType.Watch) return;
var cell = ((WatchListAutoCompleteCell)sender);
selectedNode.Node.Name = cell.CommandText;
myList.UnselectAll();
if (WatchType == WatchListType.Watch && WatchPad.Instance != null) {
WatchPad.Instance.InvalidatePad();
}
selectedNode.IsEditing = false;
}
void MyListPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (SelectedNode == null) return;
if (WatchType != WatchListType.Watch)
return;
SelectedNode.IsEditing = true;
}
}
}

175
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchListAutoCompleteCell.cs

@ -1,175 +0,0 @@ @@ -1,175 +0,0 @@
// 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.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.AvalonEdit;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Pads.Controls
{
public partial class WatchListAutoCompleteCell : UserControl
{
string language;
protected ConsoleControl console;
public static readonly DependencyProperty CommandTextProperty =
DependencyProperty.Register("CommandText", typeof(string), typeof(WatchListAutoCompleteCell),
new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandTextChanged)));
NRefactoryResolver resolver;
public event EventHandler CommandEntered;
public WatchListAutoCompleteCell()
{
InitializeComponent();
console = new ConsoleControl();
console.TextAreaTextEntered += new TextCompositionEventHandler(consoleControl_TextAreaTextEntered);
console.TextAreaPreviewKeyDown += new KeyEventHandler(console_TextAreaPreviewKeyDown);
console.LostFocus += new RoutedEventHandler(console_LostFocus);
console.HideScrollBar();
ConsolePanel.Content = console;
// get language
if (ProjectService.CurrentProject == null)
language = "C#";
else
language = ProjectService.CurrentProject.Language;
resolver = new NRefactoryResolver(LanguageProperties.GetLanguage(language));
// FIXME set language
if (language == "VB" || language == "VBNet") {
console.SetHighlighting("VBNET");
}
else {
console.SetHighlighting("C#");
}
// get process
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
debugger.ProcessSelected += delegate(object sender, ProcessEventArgs e) {
this.Process = e.Process;
};
this.Process = debugger.DebuggedProcess;
}
Process Process { get; set; }
/// <summary>
/// Gets/sets the command text displayed at the command prompt.
/// </summary>
public string CommandText {
get { return console.CommandText.Trim(); }
set { console.CommandText = value; }
}
ITextEditor TextEditor {
get {
return console.TextEditor;
}
}
void console_TextAreaPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return || e.Key == Key.Escape) {
if (e.Key == Key.Escape)
CommandText = string.Empty;
else {
if(!CheckSyntax())
return;
}
if (CommandEntered != null)
CommandEntered(this, EventArgs.Empty);
e.Handled = true;
}
}
void console_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(CommandText) || !this.CheckSyntax())
return;
if (CommandEntered != null)
CommandEntered(this, EventArgs.Empty);
}
bool CheckSyntax()
{
string command = CommandText;
// FIXME workaround the NRefactory issue that needs a ; at the end
if (language == "C#" || language == "CSharp") {
if (!command.EndsWith(";"))
command += ";";
// FIXME only one string should be available; highlighting expects C#, supported language, CSharp
language = "CSharp";
}
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language.ToString(), true);
using (var parser = ParserFactory.CreateParser(supportedLanguage, new StringReader(command))) {
parser.ParseExpression();
if (parser.Errors.Count > 0) {
MessageService.ShowError(parser.Errors.ErrorOutput);
return false;
}
}
return true;
}
void consoleControl_TextAreaTextEntered(object sender, TextCompositionEventArgs e)
{
foreach (char ch in e.Text) {
if (ch == '.') {
ShowDotCompletion(console.CommandText);
}
}
}
void ShowDotCompletion(string currentText)
{
var seg = Process.SelectedStackFrame.NextStatement;
var expressionFinder = ParserService.GetExpressionFinder(seg.Filename);
var info = ParserService.GetParseInformation(seg.Filename);
string text = ParserService.GetParseableFileContent(seg.Filename).Text;
int currentOffset = TextEditor.Caret.Offset - console.CommandOffset - 1;
var expr = expressionFinder.FindExpression(currentText, currentOffset);
expr.Region = new DomRegion(seg.StartLine, seg.StartColumn, seg.EndLine, seg.EndColumn);
var rr = resolver.Resolve(expr, info, text);
if (rr != null) {
TextEditor.ShowCompletionWindow(new DotCodeCompletionItemProvider().GenerateCompletionListForResolveResult(rr, expr.Context));
}
}
static void OnCommandTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var cell = d as WatchListAutoCompleteCell;
if (cell != null && e.NewValue != null) {
cell.CommandText = e.NewValue.ToString();
}
}
}
}

11
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchListAutoCompleteCell.xaml

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
<UserControl x:Class="Debugger.AddIn.Pads.Controls.WatchListAutoCompleteCell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
</Grid.ColumnDefinitions>
<ContentPresenter
Name="ConsolePanel" />
</Grid>
</UserControl>

85
src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerPad.cs

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Windows.Controls;
using Debugger;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public abstract class DebuggerPad : AbstractPadContent
{
protected DockPanel panel;
ToolBar toolbar;
protected WindowsDebugger debugger;
public override object Control {
get {
return panel;
}
}
public DebuggerPad()
{
// UI
this.panel = new DockPanel();
this.toolbar = BuildToolBar();
if (this.toolbar != null) {
this.toolbar.SetValue(DockPanel.DockProperty, Dock.Top);
this.panel.Children.Add(toolbar);
}
// logic
debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
InitializeComponents();
debugger.ProcessSelected += delegate(object sender, ProcessEventArgs e) {
SelectProcess(e.Process);
};
SelectProcess(debugger.DebuggedProcess);
}
protected virtual void InitializeComponents()
{
}
protected virtual void SelectProcess(Process process)
{
}
/// <summary>
/// Never call this directly. Always use InvalidatePad()
/// </summary>
protected virtual void RefreshPad()
{
}
bool invalidatePadEnqueued;
public void InvalidatePad()
{
WorkbenchSingleton.AssertMainThread();
if (invalidatePadEnqueued || WorkbenchSingleton.Workbench == null)
return;
invalidatePadEnqueued = true;
WorkbenchSingleton.SafeThreadAsyncCall(
delegate {
invalidatePadEnqueued = false;
RefreshPad();
});
}
protected virtual ToolBar BuildToolBar()
{
return null;
}
}
}

120
src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Windows;
@ -11,107 +12,64 @@ using Debugger; @@ -11,107 +12,64 @@ using Debugger;
using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.Pads.ParallelPad;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class LoadedModulesPad : DebuggerPad
public class LoadedModulesPad : AbstractPadContent
{
ListView loadedModulesList;
Process debuggedProcess;
ObservableCollection<ModuleModel> loadedModules;
ListView listView;
protected override void InitializeComponents()
{
loadedModulesList = new ListView();
loadedModules = new ObservableCollection<ModuleModel>();
loadedModulesList.ItemsSource = loadedModules;
loadedModulesList.View = new GridView();
panel.Children.Add(loadedModulesList);
RedrawContent();
ResourceService.LanguageChanged += delegate { RedrawContent(); };
}
public void RedrawContent()
{
loadedModulesList.ClearColumns();
loadedModulesList.AddColumn(StringParser.Parse("${res:Global.Name}"),
new Binding { Path = new PropertyPath("Name") }, 250);
loadedModulesList.AddColumn(StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.AddressColumn}"),
new Binding { Path = new PropertyPath("Address") }, 100);
loadedModulesList.AddColumn(StringParser.Parse("${res:Global.Path}"),
new Binding { Path = new PropertyPath("Path") }, 250);
loadedModulesList.AddColumn(StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.OrderColumn}"),
new Binding { Path = new PropertyPath("Order") }, 80);
loadedModulesList.AddColumn(StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.SymbolsColumn}"),
new Binding { Path = new PropertyPath("Symbols") }, 130);
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Modules.Added -= debuggedProcess_ModuleLoaded;
debuggedProcess.Modules.Removed -= debuggedProcess_ModuleUnloaded;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Modules.Added += debuggedProcess_ModuleLoaded;
debuggedProcess.Modules.Removed += debuggedProcess_ModuleUnloaded;
}
InvalidatePad();
}
void debuggedProcess_ModuleLoaded(object sender, CollectionItemEventArgs<Module> e)
{
AddModule(e.Item);
public override object Control {
get { return listView; }
}
void debuggedProcess_ModuleUnloaded(object sender, CollectionItemEventArgs<Module> e)
public LoadedModulesPad()
{
RemoveModule(e.Item);
var res = new CommonResources();
res.InitializeComponent();
listView = new ListView();
listView.View = (GridView)res["loadedModulesGridView"];
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
protected override void RefreshPad()
void RefreshPad()
{
loadedModules.Clear();
if (debuggedProcess != null) {
foreach(Module module in debuggedProcess.Modules) {
AddModule(module);
Process process = WindowsDebugger.CurrentProcess;
List<ModuleItem> loadedModules = new List<ModuleItem>();
if (process != null) {
foreach(Module module in process.Modules) {
loadedModules.Add(new ModuleItem(module));
}
}
}
void AddModule(Module module)
{
loadedModules.Add(new ModuleModel(module));
}
void RemoveModule(Module module)
{
loadedModules.RemoveWhere(model => model.Module == module);
listView.ItemsSource = loadedModules;
}
}
static class ListViewExtensions
public class ModuleItem
{
public static void ClearColumns(this ListView view)
{
if (view == null)
throw new ArgumentNullException("view");
if (view.View is GridView)
((GridView)view.View).Columns.Clear();
}
public string Name { get; private set; }
public string Address { get; private set; }
public string Path { get; private set; }
public string Order { get; private set; }
public string Symbols { get; private set; }
public static void AddColumn(this ListView view, string header, Binding binding, double width)
public ModuleItem(Module module)
{
if (view == null)
throw new ArgumentNullException("view");
if (view.View is GridView) {
GridViewColumn column = new GridViewColumn {
Width = width,
DisplayMemberBinding = binding,
Header = header };
((GridView)view.View).Columns.Add(column);
this.Name = module.Name;
this.Address = string.Format("{0:X8}", module.BaseAdress);
if (module.IsDynamic) {
this.Path = StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.DynamicModule}");
} else if (module.IsInMemory) {
this.Path = StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.InMemoryModule}");
} else {
this.Path = module.FullPath;
}
this.Order = module.OrderOfLoading.ToString();
this.Symbols = module.HasSymbols ? StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.HasSymbols}") : StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.HasNoSymbols}");
}
}
}

88
src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs

@ -1,85 +1,55 @@ @@ -1,85 +1,55 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
using Debugger;
using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using Exception = System.Exception;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class LocalVarPad : DebuggerPad
public class LocalVarPad : AbstractPadContent
{
WatchList localVarList;
Process debuggedProcess;
static LocalVarPad instance;
SharpTreeView tree;
public LocalVarPad()
{
instance = this;
}
/// <remarks>Always check if Instance is null, might be null if pad is not opened!</remarks>
public static LocalVarPad Instance {
get { return instance; }
}
public Process Process {
get { return debuggedProcess; }
}
protected override void InitializeComponents()
{
localVarList = new WatchList(WatchListType.LocalVar);
panel.Children.Add(localVarList);
public override object Control {
get { return tree; }
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_Paused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_Paused;
}
InvalidatePad();
SharpTreeNodeCollection Items {
get { return tree.Root.Children; }
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
public LocalVarPad()
{
InvalidatePad();
var res = new CommonResources();
res.InitializeComponent();
this.tree = new SharpTreeView();
this.tree.Root = new SharpTreeNode();
this.tree.ShowRoot = false;
this.tree.View = (GridView)res["variableGridView"];
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
protected override void RefreshPad()
void RefreshPad()
{
if (debuggedProcess == null || debuggedProcess.IsRunning) {
localVarList.WatchItems.Clear();
return;
}
StackFrame frame = WindowsDebugger.CurrentStackFrame;
LoggingService.Info("Local Variables refresh");
try {
StackFrame frame = debuggedProcess.GetCurrentExecutingFrame();
localVarList.WatchItems.Clear();
if (frame == null) return;
debuggedProcess.EnqueueForEach(
if (frame == null) {
this.Items.Clear();
} else {
this.Items.Clear();
frame.Process.EnqueueForEach(
Dispatcher.CurrentDispatcher,
new StackFrameNode(frame).ChildNodes.ToList(),
n => localVarList.WatchItems.Add(n.ToSharpTreeNode())
ValueNode.GetLocalVariables().ToList(),
n => this.Items.Add(n.ToSharpTreeNode())
);
} catch (Exception ex) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
MessageService.ShowException(ex);
}
}
}
}

331
src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs

@ -1,331 +0,0 @@ @@ -1,331 +0,0 @@
// 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.ComponentModel;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Controls;
using Debugger;
using Debugger.Interop;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Debugging;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public sealed class MemoryPad : DebuggerPad
{
int currentAddressIndex;
ConsoleControl console;
int columnsNumber = 16;
byte displayByteSize = 1;
byte[] memory;
Process debuggedProcess;
List<Tuple<long, long>> memoryAddresses = new List<Tuple<long, long>>();
Dictionary<long, int> addressesMapping = new Dictionary<long, int>();
/// <summary>
/// Gets or sets the number of columns in the display
/// </summary>
[DefaultValue(16)]
public int ColumnsNumber {
get { return columnsNumber; }
set {
if (value != columnsNumber) {
columnsNumber = value;
}
}
}
/// <summary>
/// Gets or sets the display byte size: 1, 2, 4
/// </summary>
[DefaultValue(1)]
public byte DisplayByteSize {
get { return displayByteSize; }
set {
// check is value is a power of 2 between 1 and 4.
if ((value & (value - 1)) != 0)
return;
if (value < 1 || value > 4)
return;
if (displayByteSize != value) {
displayByteSize = value;
}
}
}
public MemoryPad()
{
this.console = new ConsoleControl();
this.panel.Children.Add(console);
this.console.Encoding = Encoding.Default;
RefreshPad(); // exception
this.console.SetReadonly();
DebuggerService.DebugStopped += DebuggerService_DebugStopped;
}
void DebuggerService_DebugStopped(object sender, EventArgs e)
{
memoryAddresses.Clear();
addressesMapping.Clear();
memory = null;
}
protected override ToolBar BuildToolBar()
{
return ToolBarService.CreateToolBar(panel, this, "/SharpDevelop/Pads/MemoryPad/ToolBar");
}
protected override void SelectProcess(Process process)
{
if (process == null)
return;
debuggedProcess = process;
memoryAddresses = debuggedProcess.GetVirtualMemoryAddresses();
currentAddressIndex = 0;
}
public void JumpToAddress(string address)
{
try {
if (address.StartsWith("0x"))
address = address.Substring(2);
long addr = Int64.Parse(address, NumberStyles.AllowHexSpecifier);
memoryAddresses = debuggedProcess.GetVirtualMemoryAddresses();
// find index for the address or the near addess
currentAddressIndex = memoryAddresses.BinarySearch(addr);
if (currentAddressIndex == -1) {
MessageService.ShowMessage(
string.Format(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.AddressNotFound"), address),
ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad"));
currentAddressIndex = 0;
return;
}
// refresh pad
if (!Refresh())
return;
// find line
long mod = addr % (columnsNumber * displayByteSize);
int line;
long key = addr - mod;
//int index = addressesMapping.BinarySearch(key);
if (addressesMapping.ContainsKey(key))
line = addressesMapping[key];
else
line = 1;
// jump
console.SelectText(line, 0, 8);
console.JumpToLine(line);
} catch (System.Exception ex) {
LoggingService.Error(ex.Message);
}
}
public bool Refresh(bool refreshMemoryAddresses = false)
{
if (console == null)
return false;
console.Clear();
if (debuggedProcess == null || debugger.IsProcessRunning) {
console.Append(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.NotDebuggingOrProcessRunning"));
return false;
}
if (currentAddressIndex <= -1) {
console.Append(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.NoMappings"));
currentAddressIndex = -1;
return false;
}
if (refreshMemoryAddresses)
memoryAddresses = debuggedProcess.GetVirtualMemoryAddresses();
if (memoryAddresses.Count == 0) {
console.Append(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.NoMappings"));
return false;
}
if (currentAddressIndex >= memoryAddresses.Count) {
console.Append(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.NoMappings"));
currentAddressIndex = memoryAddresses.Count ;
return false;
}
RetrieveMemory();
return true;
}
void RetrieveMemory()
{
// refresh data
addressesMapping.Clear();
// get current address
var item = memoryAddresses[currentAddressIndex];
long address = item.Item1;
long size = item.Item2;
memory = debuggedProcess.ReadProcessMemory(address, size);
if (memory == null) {
console.Append(string.Format(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.UnableToReadFormat"), address.ToString("X8"), size));
return;
}
DisplayMemory();
}
public void DisplayMemory()
{
if (memory == null || memory.Length == 0)
return;
if (console == null)
return;
console.Clear();
addressesMapping.Clear();
var item = memoryAddresses[currentAddressIndex];
long address = item.Item1;
int totalBytesPerRow = columnsNumber * displayByteSize;
int numberOfLines = memory.Length / totalBytesPerRow;
int remainingMemory = memory.Length % totalBytesPerRow;
int currentLine = 2;// line in the console
int index = 0;// index in memory arrray of current line
StringBuilder sb = new StringBuilder();
sb.Append(string.Format(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.ReadingFromFormat"), address.ToString("X8"), (address + memory.Length).ToString("X8"), memory.Length));
sb.Append(Environment.NewLine);
while (index < numberOfLines) {
addressesMapping.Add(address, currentLine);
// write address
sb.Append(address.ToString("X8"));
address += (long)totalBytesPerRow;
sb.Append(" ");
// write bytes
int start = index * totalBytesPerRow;
for (int i = 0; i < columnsNumber; ++i) {
for (int j = 0; j < displayByteSize; ++j) {
sb.Append(memory[start++].ToString("X2"));
}
sb.Append(" ");
}
// write chars
start = index * totalBytesPerRow;
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < totalBytesPerRow; ++i) {
sb1.Append(((char)memory[start++]).ToString());
}
string s = sb1.ToString();
s = Regex.Replace(s, "\\r\\n", string.Empty);
s = Regex.Replace(s, "\\n", string.Empty);
s = Regex.Replace(s, "\\r", string.Empty);
sb.Append(s);
sb.Append(Environment.NewLine);
currentLine++;
index++;
}
// write the rest of memory
if (remainingMemory != 0) {
addressesMapping.Add(address, currentLine);
// write address
sb.Append(address.ToString("X8"));
sb.Append(" ");
// write bytes
int start = index * remainingMemory * displayByteSize;
for (int i = 0; i < remainingMemory; ++i) {
for (int j = 0; j < displayByteSize; j++) {
sb.Append(memory[start++].ToString("X2"));
}
sb.Append(" ");
}
// write chars
start = index * remainingMemory * displayByteSize;
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < remainingMemory * displayByteSize; ++i) {
sb1.Append(((char)memory[start++]).ToString());
}
string s = sb1.ToString();
s = Regex.Replace(s, "\\r\\n", string.Empty);
s = Regex.Replace(s, "\\n", string.Empty);
s = Regex.Replace(s, "\\r", string.Empty);
sb.Append(s);
}
console.Append(sb.ToString());
}
public void MoveToPreviousAddress()
{
currentAddressIndex--;
Refresh();
}
public void MoveToNextAddress()
{
currentAddressIndex++;
Refresh();
}
}
internal static class MemoryPadExtensions
{
/// <summary>
/// Does a binary search when the Item1 from Tuple is sorted.
/// </summary>
/// <param name="source">Source of data.</param>
/// <param name="item1">Item to search.</param>
/// <returns>The nearest index.</returns>
internal static int BinarySearch<T>(this List<Tuple<long, T>> source, long item1)
{
// base checks
if (source == null)
throw new NullReferenceException("Source is null!");
if (source.Count == 0)
return -1;
if (item1 < source[0].Item1)
return 0;
if (item1 > source[source.Count - 1].Item1)
return source.Count;
// do a binary search since the source is sorted
int first = 0; int last = source.Count;
while (first < last - 1) {
int middle = (first + last) / 2;
if (source[middle].Item1 == item1)
return middle;
else
if (source[middle].Item1 < item1)
first = middle;
else
last = middle;
}
return first;
}
}
}

72
src/AddIns/Debugger/Debugger.AddIn/Pads/ObjectGraphPad.cs

@ -1,72 +0,0 @@ @@ -1,72 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using ICSharpCode.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Debugger;
using Debugger.AddIn.Visualizers.Graph;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
/// <summary>
/// Description of ObjectGraphPad.
/// </summary>
public class ObjectGraphPad : DebuggerPad
{
Process debuggedProcess;
ObjectGraphControl objectGraphControl;
static ObjectGraphPad instance;
public ObjectGraphPad()
{
instance = this;
}
/// <remarks>Always check if Instance is null, might be null if pad is not opened!</remarks>
public static ObjectGraphPad Instance {
get { return instance; }
}
protected override void InitializeComponents()
{
objectGraphControl = new ObjectGraphControl();
panel.Children.Add(objectGraphControl);
}
protected override void RefreshPad()
{
// BUG: if pad window is undocked and floats standalone, IsVisible == false (so pad won't refresh)
// REQUEST: need to refresh when pad becomes visible -> VisibleChanged event?
if (!objectGraphControl.IsVisible)
{
return;
}
if (debuggedProcess == null || debuggedProcess.IsRunning || debuggedProcess.SelectedStackFrame == null) {
this.objectGraphControl.Clear();
return;
}
this.objectGraphControl.RefreshView();
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_Paused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_Paused;
}
InvalidatePad();
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
InvalidatePad();
}
}
}

114
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackFrameModel.cs

@ -63,118 +63,4 @@ namespace Debugger.AddIn.Pads.ParallelPad @@ -63,118 +63,4 @@ namespace Debugger.AddIn.Pads.ParallelPad
}
}
}
public class ThreadModel : ViewModelBase
{
Thread thread;
public ThreadModel(Thread thread)
{
if (thread == null)
throw new ArgumentNullException("thread");
this.thread = thread;
thread.NameChanged += delegate { RaisePropertyChanged(() => Name); };
}
public Thread Thread {
get { return thread; }
}
public uint ID {
get { return thread.ID; }
}
public string Name {
get { return thread.Name; }
}
public string Priority {
get {
switch (thread.Priority) {
case System.Threading.ThreadPriority.Highest:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Highest");
case System.Threading.ThreadPriority.AboveNormal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.AboveNormal");
case System.Threading.ThreadPriority.Normal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Normal");
case System.Threading.ThreadPriority.BelowNormal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.BelowNormal");
case System.Threading.ThreadPriority.Lowest:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Lowest");
default:
return thread.Priority.ToString();
}
}
}
public string Location {
get {
if (thread.Process.IsPaused && thread.MostRecentStackFrame != null)
return thread.MostRecentStackFrame.MethodInfo.Name;
return ResourceService.GetString("Global.NA");
}
}
public string Frozen {
get {
return ResourceService.GetString(thread.Suspended ? "Global.Yes" : "Global.No");
}
}
}
public class ModuleModel : ViewModelBase
{
Module module;
public ModuleModel(Module module)
{
if (module == null)
throw new ArgumentNullException("module");
this.module = module;
this.module.SymbolsUpdated += delegate {
RaisePropertyChanged(() => Name);
RaisePropertyChanged(() => Address);
RaisePropertyChanged(() => Path);
RaisePropertyChanged(() => Order);
RaisePropertyChanged(() => Symbols);
};
}
public Module Module {
get { return module; }
}
public string Name {
get { return module.Name; }
}
public string Address {
get { return string.Format("{0:X8}", module.BaseAdress); }
}
public string Path {
get {
if (module.IsDynamic)
return StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.DynamicModule}");
if (module.IsInMemory)
return StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.InMemoryModule}");
return module.FullPath;
}
}
public string Order {
get {
return module.OrderOfLoading.ToString();
}
}
public string Symbols {
get {
if (module.HasSymbols)
return StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.HasSymbols}");
return StringParser.Parse("${res:MainWindow.Windows.Debug.Modules.HasNoSymbols}");
}
}
}
}

91
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs

@ -20,6 +20,7 @@ using ICSharpCode.SharpDevelop.Bookmarks; @@ -20,6 +20,7 @@ using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
@ -29,43 +30,45 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -29,43 +30,45 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
Tasks
}
public class ParallelStackPad : DebuggerPad
public class ParallelStackPad : AbstractPadContent
{
DockPanel panel;
ToolBar toolbar;
DrawSurface surface;
Process debuggedProcess;
ParallelStacksGraph graph;
List<ThreadStack> currentThreadStacks = new List<ThreadStack>();
ParallelStacksView parallelStacksView;
StackFrame selectedFrame;
bool isMethodView;
public override object Control {
get { return panel; }
}
#region Overrides
protected override void InitializeComponents()
public ParallelStackPad()
{
this.panel = new DockPanel();
this.toolbar = ToolBarService.CreateToolBar(panel, this, "/SharpDevelop/Pads/ParallelStacksPad/ToolBar");
this.toolbar.SetValue(DockPanel.DockProperty, Dock.Top);
this.panel.Children.Add(toolbar);
surface = new DrawSurface();
panel.Children.Add(surface);
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= OnProcessPaused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += OnProcessPaused;
}
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
DebuggerService.DebugStarted += OnReset;
DebuggerService.DebugStopped += OnReset;
InvalidatePad();
DebuggerService.DebugStopped += OnReset;
}
protected override void RefreshPad()
protected void RefreshPad()
{
Process debuggedProcess = WindowsDebugger.CurrentProcess;
if (debuggedProcess == null || debuggedProcess.IsRunning) {
return;
}
@ -95,12 +98,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -95,12 +98,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (isMethodView)
{
// build method view for threads
CreateMethodViewStacks();
CreateMethodViewStacks(debuggedProcess);
}
else
{
// normal view
CreateCommonStacks();
CreateCommonStacks(debuggedProcess);
}
}
@ -119,11 +122,6 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -119,11 +122,6 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
surface.SetGraph(graph);
}
}
protected override ToolBar BuildToolBar()
{
return ToolBarService.CreateToolBar(panel, this, "/SharpDevelop/Pads/ParallelStacksPad/ToolBar");
}
#endregion
@ -133,7 +131,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -133,7 +131,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
get { return parallelStacksView; }
set {
parallelStacksView = value;
InvalidatePad();
WindowsDebugger.RefreshPads();
}
}
@ -141,7 +139,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -141,7 +139,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
get { return isMethodView; }
set {
isMethodView = value;
InvalidatePad();
WindowsDebugger.RefreshPads();
}
}
@ -163,11 +161,6 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -163,11 +161,6 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
BookmarkManager.RemoveAll(b => b is SelectedFrameBookmark);
}
void OnProcessPaused(object sender, ProcessEventArgs e)
{
InvalidatePad();
}
void AddChildren(ThreadStack parent)
{
if(parent.ThreadStackChildren == null || parent.ThreadStackChildren.Count == 0)
@ -187,7 +180,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -187,7 +180,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
}
void CreateCommonStacks()
void CreateCommonStacks(Process debuggedProcess)
{
// stack.ItemCollection order
// 0 -> top of stack = S.C
@ -311,7 +304,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -311,7 +304,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
commonParent.Process = debuggedProcess;
commonParent.StackSelected += OnThreadStackSelected;
commonParent.FrameSelected += OnFrameSelected;
commonParent.IsSelected = commonParent.ThreadIds.Contains(debuggedProcess.SelectedThread.ID);
commonParent.IsSelected = commonParent.ThreadIds.Contains(WindowsDebugger.CurrentThread.ID);
// add new children
foreach (var stack in listOfCurrentStacks) {
if (stack.ItemCollection.Count == 0)
@ -369,7 +362,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -369,7 +362,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
}
void CreateMethodViewStacks()
void CreateMethodViewStacks(Process debuggedProcess)
{
var list = new List<Tuple<ObservableCollection<ParallelStackFrameModel>, ObservableCollection<ParallelStackFrameModel>, List<uint>>>();
@ -439,6 +432,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -439,6 +432,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
void CreateThreadStack(Thread thread)
{
Process debuggedProcess = thread.Process;
Thread currentThread = WindowsDebugger.CurrentThread;
var items = CreateItems(thread);
if (items == null || items.Count == 0)
return;
@ -450,10 +446,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -450,10 +446,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
threadStack.ItemCollection = items;
threadStack.UpdateThreadIds(parallelStacksView == ParallelStacksView.Tasks, thread.ID);
if (debuggedProcess.SelectedThread != null) {
threadStack.IsSelected = threadStack.ThreadIds.Contains(debuggedProcess.SelectedThread.ID);
if (currentThread != null) {
threadStack.IsSelected = threadStack.ThreadIds.Contains(currentThread.ID);
if (selectedFrame == null)
selectedFrame = debuggedProcess.SelectedStackFrame;
selectedFrame = WindowsDebugger.CurrentStackFrame;
}
currentThreadStacks.Add(threadStack);
@ -465,6 +461,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -465,6 +461,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
int noTasks = 0;
var result = new ObservableCollection<ParallelStackFrameModel>();
var callstack = thread.GetCallstack(100);
Process debuggedProcess = thread.Process;
if (parallelStacksView == ParallelStacksView.Threads) {
foreach (StackFrame frame in callstack) {
@ -492,10 +489,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -492,10 +489,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
threadStack.ItemCollection = result.Clone();
threadStack.UpdateThreadIds(true, frame.Thread.ID);
if (debuggedProcess.SelectedThread != null) {
threadStack.IsSelected = threadStack.ThreadIds.Contains(debuggedProcess.SelectedThread.ID);
if (WindowsDebugger.CurrentThread != null) {
threadStack.IsSelected = threadStack.ThreadIds.Contains(WindowsDebugger.CurrentThread.ID);
if (selectedFrame == null)
selectedFrame = debuggedProcess.SelectedStackFrame;
selectedFrame = WindowsDebugger.CurrentStackFrame;
}
currentThreadStacks.Add(threadStack);
@ -535,10 +532,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -535,10 +532,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
lastItemIsExternalMethod = true;
}
if (frame.Thread.SelectedStackFrame != null &&
frame.Thread.ID == debuggedProcess.SelectedThread.ID &&
frame.Thread.SelectedStackFrame.IP == frame.IP &&
frame.Thread.SelectedStackFrame.GetMethodName() == frame.GetMethodName()) {
if (frame.Thread.MostRecentStackFrame != null &&
frame.Thread.ID == WindowsDebugger.CurrentThread.ID &&
frame.Thread.MostRecentStackFrame.IP == frame.IP &&
frame.Thread.MostRecentStackFrame.GetMethodName() == frame.GetMethodName()) {
model.Image = PresentationResourceService.GetImage("Bookmarks.CurrentLine").Source;
model.IsRunningStackFrame = true;
} else {
@ -583,7 +580,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -583,7 +580,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
ToggleSelectedFrameBookmark(e.Location);
if (isMethodView)
InvalidatePad();
WindowsDebugger.RefreshPads();
}
#endregion

9
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ThreadStack.xaml.cs

@ -5,15 +5,16 @@ using System; @@ -5,15 +5,16 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Pads.ParallelPad
{
@ -183,7 +184,7 @@ namespace Debugger.AddIn.Pads.ParallelPad @@ -183,7 +184,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
if (selectedItem == null)
return;
var thread = Process.Threads.Find(t => t.ID == threadId);
var thread = Process.Threads.FirstOrDefault(t => t.ID == threadId);
if (thread == null)
return;
@ -233,7 +234,7 @@ namespace Debugger.AddIn.Pads.ParallelPad @@ -233,7 +234,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
foreach (var id in ThreadIds) {
MenuItem m = new MenuItem();
m.IsCheckable = true;
m.IsChecked = id == Process.SelectedThread.ID;
m.IsChecked = id == WindowsDebugger.CurrentThread.ID;
m.Click += delegate(object sender, RoutedEventArgs e) {
var menuItem = e.OriginalSource as MenuItem;
SelectFrame((uint)menuItem.Tag, item);
@ -270,7 +271,7 @@ namespace Debugger.AddIn.Pads.ParallelPad @@ -270,7 +271,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
if (selectedItem.MethodName == frame.GetMethodName())
{
TextBlock tb = new TextBlock();
tb.Text = thread.ID + ": " + CallStackPadContent.GetFullName(frame);
tb.Text = thread.ID + ": " + CallStackPad.GetFullName(frame);
panel.Children.Add(tb);
}
}

65
src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.Menu.cs

@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Collections;
using System.Dynamic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Debugger;
using Debugger.AddIn.Pads.ParallelPad;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public partial class RunningThreadsPad
{
ContextMenu CreateContextMenuStrip()
{
ContextMenu menu = new ContextMenu();
menu.Opened += FillContextMenuStrip;
return menu;
}
void FillContextMenuStrip(object sender, RoutedEventArgs e)
{
var items = runningThreadsList.SelectedItems;
if (items == null || items.Count == 0) {
e.Handled = true;
return;
}
ThreadModel item = items[0] as ThreadModel;
if (item == null)
return;
ContextMenu menu = sender as ContextMenu;
menu.Items.Clear();
MenuItem freezeItem;
freezeItem = new MenuItem();
freezeItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.Threads.Freeze");
freezeItem.IsChecked = item.Thread.Suspended;
freezeItem.Click +=
delegate {
if (items == null || items.Count == 0) {
e.Handled = true;
return;
}
bool suspended = item.Thread.Suspended;
if (!debuggedProcess.IsPaused) {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotFreezeWhileRunning}", "${res:MainWindow.Windows.Debug.Threads.Freeze}");
return;
}
foreach(ThreadModel current in items.OfType<ThreadModel>()) {
current.Thread.Suspended = !suspended;
}
InvalidatePad();
};
menu.Items.Add(freezeItem);
}
}
}

154
src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.cs

@ -1,154 +0,0 @@ @@ -1,154 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Threading;
using Debugger;
using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.Pads.ParallelPad;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
using Exception = System.Exception;
using Thread = Debugger.Thread;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public partial class RunningThreadsPad : DebuggerPad
{
ListView runningThreadsList;
ObservableCollection<ThreadModel> runningThreads;
Process debuggedProcess;
protected override void InitializeComponents()
{
runningThreads = new ObservableCollection<ThreadModel>();
runningThreadsList = new ListView();
runningThreadsList.ContextMenu = CreateContextMenuStrip();
runningThreadsList.MouseDoubleClick += RunningThreadsListItemActivate;
runningThreadsList.ItemsSource = runningThreads;
runningThreadsList.View = new GridView();
panel.Children.Add(runningThreadsList);
RedrawContent();
ResourceService.LanguageChanged += delegate { RedrawContent(); };
}
public void RedrawContent()
{
runningThreadsList.ClearColumns();
runningThreadsList.AddColumn(ResourceService.GetString("Global.ID"),
new Binding { Path = new PropertyPath("ID") },
100);
runningThreadsList.AddColumn(ResourceService.GetString("Global.Name"),
new Binding { Path = new PropertyPath("Name") },
300);
runningThreadsList.AddColumn(ResourceService.GetString("AddIns.HtmlHelp2.Location"),
new Binding { Path = new PropertyPath("Location") },
250);
runningThreadsList.AddColumn(ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority"),
new Binding { Path = new PropertyPath("Priority") },
120);
runningThreadsList.AddColumn(ResourceService.GetString("MainWindow.Windows.Debug.Threads.Frozen"),
new Binding { Path = new PropertyPath("Frozen") },
80);
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_Paused;
debuggedProcess.Threads.Added -= debuggedProcess_ThreadStarted;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_Paused;
debuggedProcess.Threads.Added += debuggedProcess_ThreadStarted;
}
runningThreads.Clear();
InvalidatePad();
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
InvalidatePad();
}
void debuggedProcess_ThreadStarted(object sender, CollectionItemEventArgs<Thread> e)
{
AddThread(e.Item);
}
protected override void RefreshPad()
{
if (debuggedProcess == null || debuggedProcess.IsRunning) {
runningThreads.Clear();
return;
}
LoggingService.Info("Threads refresh");
debuggedProcess.EnqueueForEach(
Dispatcher.CurrentDispatcher,
debuggedProcess.Threads.ToList(),
t => AddThread(t)
);
}
void RunningThreadsListItemActivate(object sender, EventArgs e)
{
if (debuggedProcess != null) {
if (debuggedProcess.IsPaused) {
ThreadModel obj = runningThreadsList.SelectedItems[0] as ThreadModel;
Thread thread = obj.Thread;
// check for options - if these options are enabled, selecting the frame should not continue
if ((thread.MostRecentStackFrame == null || !thread.MostRecentStackFrame.HasSymbols) &&
!DebuggingOptions.Instance.DecompileCodeWithoutSymbols) {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotSwitchWithoutDecompiledCodeOptions}",
"${res:MainWindow.Windows.Debug.Threads.ThreadSwitch}");
return;
}
debuggedProcess.SelectedThread = thread;
debuggedProcess.SelectedThread.SelectedStackFrame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (debuggedProcess.SelectedThread.SelectedStackFrame != null) {
debuggedProcess.PauseSession.PausedReason = PausedReason.CurrentThreadChanged;
debuggedProcess.OnPaused(); // Force refresh of pads - artificial pause
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotSwitchOnNAFrame}", "${res:MainWindow.Windows.Debug.Threads.ThreadSwitch}");
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.Threads.ThreadSwitch}");
}
}
}
void AddThread(Thread thread)
{
if (thread == null) return;
// remove the object if exists
RemoveThread(thread);
ThreadModel obj = new ThreadModel(thread);
runningThreads.Add(obj);
thread.Exited += (s, e) => RemoveThread(e.Thread);
}
void RemoveThread(Thread thread)
{
if (thread == null)
return;
runningThreads.RemoveWhere(model => model.Thread == thread);
}
}
}

138
src/AddIns/Debugger/Debugger.AddIn/Pads/ThreadsPad.cs

@ -0,0 +1,138 @@ @@ -0,0 +1,138 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Debugger;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Services;
using Thread = Debugger.Thread;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class ThreadsPad : AbstractPadContent
{
ListView listView;
public override object Control {
get { return listView; }
}
public ThreadsPad()
{
var res = new CommonResources();
res.InitializeComponent();
ContextMenu contextMenu = new ContextMenu();
contextMenu.Opened += FillContextMenuStrip;
listView = new ListView();
listView.View = (GridView)res["theadsGridView"];
listView.ContextMenu = contextMenu;
listView.MouseDoubleClick += listView_MouseDoubleClick;
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
void RefreshPad()
{
Process process = WindowsDebugger.CurrentProcess;
if (process == null || process.IsRunning) {
listView.ItemsSource = null;
} else {
List<ThreadItem> items = new List<ThreadItem>();
foreach(var thread in process.Threads) {
items.Add(new ThreadItem(thread));
}
listView.ItemsSource = items;
}
}
void listView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ThreadItem item = listView.SelectedItem as ThreadItem;
if (WindowsDebugger.CurrentProcess != null) {
if (WindowsDebugger.CurrentProcess.IsPaused) {
WindowsDebugger.CurrentThread = item.Thread;
WindowsDebugger.Instance.JumpToCurrentLine();
WindowsDebugger.RefreshPads();
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.Threads.ThreadSwitch}");
}
}
}
void FillContextMenuStrip(object sender, RoutedEventArgs e)
{
var items = listView.SelectedItems.OfType<ThreadItem>();
// Suspended property is safe to access at any point
bool suspended = items.All(t => t.Thread.Suspended);
ContextMenu menu = sender as ContextMenu;
menu.Items.Clear();
MenuItem freezeItem;
freezeItem = new MenuItem();
freezeItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.Threads.Freeze");
freezeItem.IsChecked = suspended;
freezeItem.Click += delegate {
if (WindowsDebugger.CurrentProcess == null || WindowsDebugger.CurrentProcess.IsRunning) {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotFreezeWhileRunning}", "${res:MainWindow.Windows.Debug.Threads.Freeze}");
return;
}
foreach(ThreadItem item in items.OfType<ThreadItem>()) {
item.Thread.Suspended = !suspended;
}
WindowsDebugger.RefreshPads();
};
menu.Items.Add(freezeItem);
}
}
public class ThreadItem
{
public Thread Thread { get; private set; }
public uint ID { get; private set; }
public string Name { get; private set; }
public string Priority { get; private set; }
public string Frozen { get; private set; }
public ThreadItem(Thread thread)
{
// We want to egarly evaluate the properties while the process is paused
// rather then wait until the GUI acesses them at some unspecified point
this.Thread = thread;
this.ID = thread.ID;
this.Name = thread.Name;
this.Priority = PriorityToString(thread.Priority);
this.Frozen = ResourceService.GetString(thread.Suspended ? "Global.Yes" : "Global.No");
}
static string PriorityToString(System.Threading.ThreadPriority priority)
{
switch (priority) {
case System.Threading.ThreadPriority.Highest:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Highest");
case System.Threading.ThreadPriority.AboveNormal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.AboveNormal");
case System.Threading.ThreadPriority.Normal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Normal");
case System.Threading.ThreadPriority.BelowNormal:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.BelowNormal");
case System.Threading.ThreadPriority.Lowest:
return ResourceService.GetString("MainWindow.Windows.Debug.Threads.Priority.Lowest");
default:
return ResourceService.GetString("Global.NA");
}
}
}
}

35
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchInputBox.xaml

@ -1,35 +0,0 @@ @@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<src:BaseWatchBox
x:Class="Debugger.AddIn.Pads.WatchInputBox" xmlns:src="clr-namespace:ICSharpCode.SharpDevelop.Gui.Pads;assembly=ICSharpCode.SharpDevelop" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:widgets="http://icsharpcode.net/sharpdevelop/widgets"
Style="{x:Static core:GlobalStyles.DialogWindowStyle}"
WindowStartupLocation="CenterScreen"
WindowState="Normal"
WindowStyle="ToolWindow"
Width="300"
SizeToContent="Height"
ResizeMode="NoResize">
<DockPanel Margin="4">
<widgets:UniformGridWithSpacing
Columns="2"
DockPanel.Dock="Bottom"
Margin="0,8"
Grid.Row="1"
HorizontalAlignment="Center">
<Button
Name="AcceptButton"
Style="{x:Static core:GlobalStyles.ButtonStyle}"
Content="{core:Localize Global.OKButtonText}"
Click="AcceptButton_Click"
IsDefault="True" />
<Button
Name="CancelButton"
Style="{x:Static core:GlobalStyles.ButtonStyle}"
Content="{core:Localize Global.CancelButtonText}"
Click="CancelButton_Click"
IsCancel="True" />
</widgets:UniformGridWithSpacing>
<ContentPresenter
MaxHeight="75"
Name="ConsolePanel" />
</DockPanel>
</src:BaseWatchBox>

170
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchInputBox.xaml.cs

@ -1,170 +0,0 @@ @@ -1,170 +0,0 @@
// 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.IO;
using System.Windows;
using System.Windows.Input;
using ICSharpCode.AvalonEdit;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Pads
{
/// <summary>
/// Interaction logic for WatchBox.xaml
/// </summary>
public partial class WatchInputBox : BaseWatchBox
{
NRefactoryResolver resolver;
SupportedLanguage language;
public SupportedLanguage ScriptLanguage {
get { return language; }
}
public WatchInputBox(string text, string caption) : base()
{
InitializeComponent();
// UI
text = StringParser.Parse(text);
this.Title = StringParser.Parse(caption);
this.ConsolePanel.Content = console;
if (ProjectService.CurrentProject == null)
language = GetLanguageFromActiveViewContent();
else
language = GetLanguage(ProjectService.CurrentProject.Language);
resolver = new NRefactoryResolver(LanguageProperties.GetLanguage(language.ToString()));
switch (language) {
case SupportedLanguage.CSharp:
console.SetHighlighting("C#");
break;
case SupportedLanguage.VBNet:
console.SetHighlighting("VBNET");
break;
}
// get process
this.Process = ((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess;
}
private Process Process { get; set; }
protected override void AbstractConsolePadTextEntered(object sender, TextCompositionEventArgs e)
{
if (this.Process == null || this.Process.IsRunning)
return;
if (this.Process.SelectedStackFrame == null || this.Process.SelectedStackFrame.NextStatement == null)
return;
foreach (char ch in e.Text) {
if (ch == '.') {
ShowDotCompletion(console.CommandText);
}
}
}
void ShowDotCompletion(string currentText)
{
var seg = Process.SelectedStackFrame.NextStatement;
var expressionFinder = ParserService.GetExpressionFinder(seg.Filename);
var info = ParserService.GetParseInformation(seg.Filename);
string text = ParserService.GetParseableFileContent(seg.Filename).Text;
int currentOffset = TextEditor.Caret.Offset - console.CommandOffset - 1;
var expr = expressionFinder.FindExpression(currentText, currentOffset);
expr.Region = new DomRegion(seg.StartLine, seg.StartColumn, seg.EndLine, seg.EndColumn);
var rr = resolver.Resolve(expr, info, text);
if (rr != null) {
TextEditor.ShowCompletionWindow(new DotCodeCompletionItemProvider().GenerateCompletionListForResolveResult(rr, expr.Context));
}
}
bool CheckSyntax()
{
string command = console.CommandText.Trim();
// FIXME workaround the NRefactory issue that needs a ; at the end
if (language == SupportedLanguage.CSharp && !command.EndsWith(";"))
command += ";";
using (var parser = ParserFactory.CreateParser(language, new StringReader(command))) {
parser.ParseExpression();
if (parser.Errors.Count > 0) {
MessageService.ShowError(parser.Errors.ErrorOutput);
return false;
}
}
return true;
}
SupportedLanguage GetLanguage(string language)
{
if ("VBNet".Equals(language, StringComparison.OrdinalIgnoreCase)
|| "VB".Equals(language, StringComparison.OrdinalIgnoreCase)
|| "VB.NET".Equals(language, StringComparison.OrdinalIgnoreCase))
return SupportedLanguage.VBNet;
return SupportedLanguage.CSharp;
}
/// <summary>
/// Gets the language used in the currently active view content. This is useful, when there is no project
/// opened and we still want to add watches (i.e. the debugger is attached to an existing process without a solution).
/// </summary>
SupportedLanguage GetLanguageFromActiveViewContent()
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
if (provider != null && provider.TextEditor != null) {
string extension = Path.GetExtension(provider.TextEditor.FileName).ToLowerInvariant();
switch (extension) {
case ".cs":
return SupportedLanguage.CSharp;
case ".vb":
return SupportedLanguage.VBNet;
}
}
return SupportedLanguage.CSharp;
}
void AcceptButton_Click(object sender, RoutedEventArgs e)
{
if (!this.CheckSyntax())
return;
this.DialogResult = true;
this.Close();
}
void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
this.Close();
}
}
}

230
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs

@ -2,14 +2,10 @@ @@ -2,14 +2,10 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml.Serialization;
using Debugger;
using Debugger.AddIn;
using Debugger.AddIn.Pads.Controls;
@ -17,198 +13,106 @@ using Debugger.AddIn.TreeModel; @@ -17,198 +13,106 @@ using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Project;
using Exception = System.Exception;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class WatchPad : DebuggerPad
public class WatchPad : AbstractPadContent
{
WatchList watchList;
Process debuggedProcess;
static WatchPad instance;
SharpTreeView tree;
/// <remarks>Always check if Instance is null, might be null if pad is not opened!</remarks>
public static WatchPad Instance {
get { return instance; }
public override object Control {
get { return tree; }
}
public WatchList WatchList {
get {
return watchList;
}
public SharpTreeView Tree {
get { return tree; }
}
public WatchPad()
{
instance = this;
public SharpTreeNodeCollection Items {
get { return tree.Root.Children; }
}
public Process Process {
get { return debuggedProcess; }
}
protected override void InitializeComponents()
{
watchList = new WatchList(WatchListType.Watch);
watchList.ContextMenu = MenuService.CreateContextMenu(this, "/SharpDevelop/Pads/WatchPad/ContextMenu");
watchList.MouseDoubleClick += WatchListDoubleClick;
watchList.WatchItems.CollectionChanged += OnWatchItemsCollectionChanged;
panel.Children.Add(watchList);
panel.KeyDown += PanelKeyDown;
// wire events that influence the items
LoadSavedNodes();
ProjectService.SolutionClosed += delegate { watchList.WatchItems.Clear(); };
ProjectService.ProjectAdded += delegate { LoadSavedNodes(); };
ProjectService.SolutionLoaded += delegate { LoadSavedNodes(); };
}
#region Saved nodes
void LoadSavedNodes()
public WatchPad()
{
var props = GetSavedVariablesProperties();
if (props == null)
return;
var res = new CommonResources();
res.InitializeComponent();
foreach (var element in props.Elements) {
watchList.WatchItems.Add(new TextNode(null, element, (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), props[element])).ToSharpTreeNode());
}
}
void OnWatchItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count > 0) {
// add to saved data
var data = e.NewItems.OfType<TextNode>().FirstOrDefault();
if (data != null) {
var props = GetSavedVariablesProperties();
if (props == null) return;
props.Set(data.FullName, data.Language.ToString());
this.tree = new SharpTreeView();
this.tree.Root = new SharpTreeNode();
this.tree.ShowRoot = false;
this.tree.View = (GridView)res["variableGridView"];
this.tree.ContextMenu = MenuService.CreateContextMenu(this, "/SharpDevelop/Pads/WatchPad/ContextMenu");
this.tree.MouseDoubleClick += delegate(object sender, MouseButtonEventArgs e) {
if (this.tree.SelectedItem == null) {
AddWatchCommand cmd = new AddWatchCommand { Owner = this };
cmd.Run();
}
}
};
if (e.Action == NotifyCollectionChangedAction.Remove) {
// remove from saved data
var data = e.OldItems.OfType<TextNode>().FirstOrDefault();
if (data != null) {
var props = GetSavedVariablesProperties();
if (props == null) return;
props.Remove(data.FullName);
}
}
}
Properties GetSavedVariablesProperties()
{
if (ProjectService.CurrentProject == null)
return null;
if (ProjectService.CurrentProject.ProjectSpecificProperties == null)
return null;
ProjectService.SolutionLoaded += delegate { LoadNodes(); };
ProjectService.SolutionClosing += delegate { SaveNodes(); };
LoadNodes();
var props = ProjectService.CurrentProject.ProjectSpecificProperties.Get("watchVars") as Properties;
if (props == null) {
ProjectService.CurrentProject.ProjectSpecificProperties.Set("watchVars", new Properties());
}
return ProjectService.CurrentProject.ProjectSpecificProperties.Get("watchVars") as Properties;
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
#endregion
void PanelKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Insert) {
AddNewWatch();
e.Handled = true;
}
}
void WatchListDoubleClick(object sender, MouseEventArgs e)
void LoadNodes()
{
if (watchList.SelectedNode == null)
if (ProjectService.OpenSolution != null &&
ProjectService.OpenSolution.Preferences != null &&
ProjectService.OpenSolution.Preferences.Properties != null)
{
AddNewWatch();
var props = ProjectService.OpenSolution.Preferences.Properties.Get("Watches", new Properties());
foreach(var element in props.Elements) {
this.Items.Add(new TreeNode(element, null).ToSharpTreeNode());
}
}
}
void AddNewWatch()
{
AddWatchCommand command = new AddWatchCommand { Owner = this };
command.Run();
}
void ResetPad(object sender, EventArgs e)
{
string language = "CSharp";
if (ProjectService.CurrentProject != null)
language = ProjectService.CurrentProject.Language;
// rebuild list
var nodes = new List<TreeNodeWrapper>();
foreach (var nod in watchList.WatchItems.OfType<TreeNodeWrapper>())
nodes.Add(new TextNode(null, nod.Node.Name,
language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp)
.ToSharpTreeNode());
watchList.WatchItems.Clear();
foreach (var nod in nodes)
watchList.WatchItems.Add(nod);
}
protected override void SelectProcess(Process process)
void SaveNodes()
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_Paused;
debuggedProcess.Exited -= ResetPad;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_Paused;
debuggedProcess.Exited += ResetPad;
if (ProjectService.OpenSolution != null &&
ProjectService.OpenSolution.Preferences != null &&
ProjectService.OpenSolution.Preferences.Properties != null)
{
var props = new Properties();
ProjectService.OpenSolution.Preferences.Properties.Set("Watches", props);
foreach(var node in this.Items.OfType<TreeNode>()) {
props.Set(node.Name, (object)null);
}
}
InvalidatePad();
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
InvalidatePad();
}
TreeNodeWrapper UpdateNode(TreeNodeWrapper node)
SharpTreeNodeAdapter MakeNode(string name)
{
LoggingService.Info("Evaluating watch: " + name);
TreeNode node;
try {
LoggingService.Info("Evaluating: " + (string.IsNullOrEmpty(node.Node.Name) ? "is null or empty!" : node.Node.Name));
var nodExpression = debugger.GetExpression(node.Node.Name);
//Value val = ExpressionEvaluator.Evaluate(nod.Name, nod.Language, debuggedProcess.SelectedStackFrame);
ExpressionNode valNode = new ExpressionNode(null, null, node.Node.Name, nodExpression);
return valNode.ToSharpTreeNode();
} catch (GetValueException) {
string error = String.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.InvalidExpression}"), node.Node.Name);
ErrorInfoNode infoNode = new ErrorInfoNode(node.Node.Name, error);
return infoNode.ToSharpTreeNode();
node = new ValueNode(null, name, () => ExpressionEvaluator.Evaluate(name, SupportedLanguage.CSharp, WindowsDebugger.CurrentStackFrame));
} catch (GetValueException e) {
node = new TreeNode("Icons.16x16.Error", name, e.Message, string.Empty, null);
}
node.CanDelete = true;
node.CanSetName = true;
node.PropertyChanged += (s, e) => { if (e.PropertyName == "Name") WindowsDebugger.RefreshPads(); };
return node.ToSharpTreeNode();
}
protected override void RefreshPad()
protected void RefreshPad()
{
if (debuggedProcess == null || debuggedProcess.IsRunning)
return;
using(new PrintTimes("Watch Pad refresh")) {
var nodes = watchList.WatchItems.OfType<TreeNodeWrapper>().ToArray();
watchList.WatchItems.Clear();
debuggedProcess.EnqueueForEach(
Process process = WindowsDebugger.CurrentProcess;
if (process != null) {
var names = this.Items.OfType<SharpTreeNodeAdapter>().Select(n => n.Node.Name).ToList();
this.Items.Clear();
process.EnqueueForEach(
Dispatcher.CurrentDispatcher,
nodes,
n => watchList.WatchItems.Add(UpdateNode(n))
names,
name => this.Items.Add(MakeNode(name))
);
}
}

49
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs

@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Text;
using Debugger.AddIn.TreeModel;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class TextNode : TreeNode, ISetText
{
public TextNode(TreeNode parent, string text, SupportedLanguage language)
: base(parent)
{
this.Name = text;
this.Language = language;
}
public override bool CanSetText {
get {
return true;
}
}
public override bool SetText(string text)
{
this.Text = text;
return true;
}
public bool SetName(string name)
{
this.Name = name;
return true;
}
public SupportedLanguage Language { get; set; }
}
public class ErrorInfoNode : ICorDebug.InfoNode
{
public ErrorInfoNode(string name, string text) : base(null, name, text)
{
IconImage = DebuggerResourceService.GetImage("Icons.16x16.Error");
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Service/DebuggeeExceptionForm.cs

@ -104,7 +104,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -104,7 +104,7 @@ namespace ICSharpCode.SharpDevelop.Services
void BtnBreakClick(object sender, EventArgs e)
{
if (this.process.SelectedThread.CurrentExceptionIsUnhandled)
if (Exception.IsUnhandled)
Close();
else if (((WindowsDebugger)DebuggerService.CurrentDebugger).BreakAndInterceptHandledException(Exception))
Close();

82
src/AddIns/Debugger/Debugger.AddIn/Service/RemotingConfigurationHelpper.cs

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
using System.Security.Policy;
namespace ICSharpCode.SharpDevelop.Services
{
[Serializable]
class RemotingConfigurationHelpper
{
public string path;
public RemotingConfigurationHelpper(string path)
{
this.path = path;
}
public static string GetLoadedAssemblyPath(string assemblyName)
{
string path = null;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
try {
string fullFilename = assembly.Location;
if (Path.GetFileName(fullFilename).Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) {
path = Path.GetDirectoryName(fullFilename);
break;
}
} catch (NotSupportedException) {
// assembly.Location throws NotSupportedException for assemblies emitted using
// Reflection.Emit by custom controls used in the forms designer
}
}
if (path == null) {
throw new Exception("Assembly " + assemblyName + " is not loaded");
}
return path;
}
public void Configure()
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
RemotingConfiguration.Configure(Path.Combine(path, "Client.config"), false);
string baseDir = Directory.GetDirectoryRoot(AppDomain.CurrentDomain.BaseDirectory);
string relDirs = AppDomain.CurrentDomain.BaseDirectory + ";" + path;
AppDomain serverAppDomain = AppDomain.CreateDomain("Debugging server",
new Evidence(AppDomain.CurrentDomain.Evidence),
baseDir,
relDirs,
AppDomain.CurrentDomain.ShadowCopyFiles);
serverAppDomain.DoCallBack(new CrossAppDomainDelegate(ConfigureServer));
}
private void ConfigureServer()
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
RemotingConfiguration.Configure(Path.Combine(path, "Server.config"), false);
}
Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
try {
string fullFilename = assembly.Location;
if (Path.GetFileNameWithoutExtension(fullFilename).Equals(args.Name, StringComparison.OrdinalIgnoreCase) ||
assembly.FullName == args.Name) {
return assembly;
}
} catch (NotSupportedException) {
// assembly.Location throws NotSupportedException for assemblies emitted using
// Reflection.Emit by custom controls used in the forms designer
}
}
return null;
}
}
}

21
src/AddIns/Debugger/Debugger.AddIn/Service/RunToCursorCommand.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Linq;
using Debugger;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
@ -14,28 +15,12 @@ namespace ICSharpCode.SharpDevelop.Services @@ -14,28 +15,12 @@ namespace ICSharpCode.SharpDevelop.Services
public override void Run()
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
WindowsDebugger winDebugger = DebuggerService.CurrentDebugger as WindowsDebugger;
if (provider == null || winDebugger == null)
if (provider == null || WindowsDebugger.CurrentProcess == null)
return;
ITextEditor textEditor = provider.TextEditor;
Breakpoint breakpoint = winDebugger.DebuggerCore.Breakpoints.Add(textEditor.FileName, null, textEditor.Caret.Line, textEditor.Caret.Column, true);
// Be careful to remove the breakpoint just once
breakpoint.Hit += delegate {
if (breakpoint != null)
breakpoint.Remove();
breakpoint = null;
};
winDebugger.DebuggedProcess.Paused += delegate {
if (breakpoint != null)
breakpoint.Remove();
breakpoint = null;
};
if (!winDebugger.IsProcessRunning) {
winDebugger.Continue();
}
WindowsDebugger.CurrentProcess.RunTo(textEditor.FileName, textEditor.Caret.Line, textEditor.Caret.Column);
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Service/SetCurrentStatementCommand.cs

@ -19,7 +19,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -19,7 +19,7 @@ namespace ICSharpCode.SharpDevelop.Services
ITextEditor textEditor = provider.TextEditor;
DebuggerService.CurrentDebugger.SetInstructionPointer(textEditor.FileName, textEditor.Caret.Line, textEditor.Caret.Column);
DebuggerService.CurrentDebugger.SetInstructionPointer(textEditor.FileName, textEditor.Caret.Line, textEditor.Caret.Column, false);
}
}
}

640
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -28,91 +28,87 @@ using ICSharpCode.SharpDevelop.Gui.OptionPanels; @@ -28,91 +28,87 @@ using ICSharpCode.SharpDevelop.Gui.OptionPanels;
using ICSharpCode.SharpDevelop.Project;
using Mono.Cecil;
using Process = Debugger.Process;
using StackFrame = Debugger.StackFrame;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace ICSharpCode.SharpDevelop.Services
{
public class WindowsDebugger : IDebugger
{
enum StopAttachedProcessDialogResult {
Detach = 0,
Terminate = 1,
Cancel = 2
}
bool useRemotingForThreadInterop = false;
bool attached;
NDebugger debugger;
ICorPublish corPublish;
Process debuggedProcess;
public static WindowsDebugger Instance { get; set; }
internal IDebuggerDecompilerService debuggerDecompilerService;
public static NDebugger CurrentDebugger { get; private set; }
public static Process CurrentProcess { get; private set; }
public static Thread CurrentThread { get; set; }
public static StackFrame CurrentStackFrame { get; set; }
//DynamicTreeDebuggerRow currentTooltipRow;
//Expression currentTooltipExpression;
public static Action RefreshingPads;
public event EventHandler<ProcessEventArgs> ProcessSelected;
public NDebugger DebuggerCore {
get {
return debugger;
public static void RefreshPads()
{
if (RefreshingPads != null) {
RefreshingPads();
}
}
public Process DebuggedProcess {
/// <summary>
/// Gets the thread which should be used for all evaluations.
/// For the time being, it is the selected thread, but we might
/// want to have a dedicated evaluation thread in the future.
/// </summary>
/// <remarks>
/// This exists for two reasons:
/// 1) So that the addin has explicit control over evaluations rather than the core
/// 2) The need to pass this to calls is a reminder that they might do evaluation
/// </remarks>
public static Thread EvalThread {
get {
return debuggedProcess;
if (CurrentProcess == null)
throw new GetValueException("Debugger is not running");
if (CurrentProcess.IsRunning)
throw new GetValueException("Process is not paused");
if (CurrentThread == null)
throw new GetValueException("No thread selected");
return CurrentThread;
}
}
public static Process CurrentProcess {
get {
WindowsDebugger dbgr = DebuggerService.CurrentDebugger as WindowsDebugger;
if (dbgr != null && dbgr.DebuggedProcess != null) {
return dbgr.DebuggedProcess;
} else {
return null;
}
}
enum StopAttachedProcessDialogResult {
Detach = 0,
Terminate = 1,
Cancel = 2
}
/// <inheritdoc/>
public bool BreakAtBeginning {
get;
set;
}
bool attached;
protected virtual void OnProcessSelected(ProcessEventArgs e)
{
if (ProcessSelected != null) {
ProcessSelected(this, e);
}
}
ICorPublish corPublish;
internal IDebuggerDecompilerService debuggerDecompilerService;
/// <inheritdoc/>
public bool BreakAtBeginning { get; set; }
public bool ServiceInitialized {
get {
return debugger != null;
}
get { return CurrentDebugger != null; }
}
public WindowsDebugger()
{
Instance = this;
}
#region IDebugger Members
string errorDebugging = "${res:XML.MainMenu.DebugMenu.Error.Debugging}";
string errorNotDebugging = "${res:XML.MainMenu.DebugMenu.Error.NotDebugging}";
string errorProcessRunning = "${res:XML.MainMenu.DebugMenu.Error.ProcessRunning}";
string errorProcessPaused = "${res:XML.MainMenu.DebugMenu.Error.ProcessPaused}";
string errorCannotStepNoActiveFunction = "${res:MainWindow.Windows.Debug.Threads.CannotStepNoActiveFunction}";
// string errorProcessRunning = "${res:XML.MainMenu.DebugMenu.Error.ProcessRunning}";
// string errorProcessPaused = "${res:XML.MainMenu.DebugMenu.Error.ProcessPaused}";
// string errorCannotStepNoActiveFunction = "${res:MainWindow.Windows.Debug.Threads.CannotStepNoActiveFunction}";
public bool IsDebugging {
get {
return ServiceInitialized && debuggedProcess != null;
return ServiceInitialized && CurrentProcess != null;
}
}
@ -124,7 +120,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -124,7 +120,7 @@ namespace ICSharpCode.SharpDevelop.Services
public bool IsProcessRunning {
get {
return IsDebugging && debuggedProcess.IsRunning;
return IsDebugging && CurrentProcess.IsRunning;
}
}
@ -143,7 +139,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -143,7 +139,7 @@ namespace ICSharpCode.SharpDevelop.Services
InitializeService();
}
string version = debugger.GetProgramVersion(processStartInfo.FileName);
string version = CurrentDebugger.GetProgramVersion(processStartInfo.FileName);
if (version.StartsWith("v1.0")) {
MessageService.ShowMessage("${res:XML.MainMenu.DebugMenu.Error.Net10NotSupported}");
@ -152,20 +148,20 @@ namespace ICSharpCode.SharpDevelop.Services @@ -152,20 +148,20 @@ namespace ICSharpCode.SharpDevelop.Services
// } else if (string.IsNullOrEmpty(version)) {
// // Not a managed assembly
// MessageService.ShowMessage("${res:XML.MainMenu.DebugMenu.Error.BadAssembly}");
} else if (debugger.IsKernelDebuggerEnabled) {
} else if (CurrentDebugger.IsKernelDebuggerEnabled) {
MessageService.ShowMessage("${res:XML.MainMenu.DebugMenu.Error.KernelDebuggerEnabled}");
} else {
attached = false;
if (DebugStarting != null)
DebugStarting(this, EventArgs.Empty);
UpdateBreakpointLines();
try {
// set the JIT flag for evaluating optimized code
Process.DebugMode = DebugModeFlag.Debug;
Process process = debugger.Start(processStartInfo.FileName,
processStartInfo.WorkingDirectory,
processStartInfo.Arguments);
SelectProcess(process);
CurrentProcess = CurrentDebugger.Start(processStartInfo.FileName, processStartInfo.WorkingDirectory, processStartInfo.Arguments, this.BreakAtBeginning);
debugger_ProcessStarted();
} catch (System.Exception e) {
// COMException: The request is not supported. (Exception from HRESULT: 0x80070032)
// COMException: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x800736B1)
@ -176,7 +172,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -176,7 +172,6 @@ namespace ICSharpCode.SharpDevelop.Services
if (e is COMException || e is BadImageFormatException || e is UnauthorizedAccessException) {
string msg = StringParser.Parse("${res:XML.MainMenu.DebugMenu.Error.CannotStartProcess}");
msg += " " + e.Message;
// TODO: Remove
if (e is COMException && ((uint)((COMException)e).ErrorCode == 0x80070032)) {
msg += Environment.NewLine + Environment.NewLine;
msg += "64-bit debugging is not supported. Please set Project -> Project Options... -> Compiling -> Target CPU to 32bit.";
@ -214,21 +209,22 @@ namespace ICSharpCode.SharpDevelop.Services @@ -214,21 +209,22 @@ namespace ICSharpCode.SharpDevelop.Services
InitializeService();
}
string version = debugger.GetProgramVersion(existingProcess.MainModule.FileName);
string version = CurrentDebugger.GetProgramVersion(existingProcess.MainModule.FileName);
if (version.StartsWith("v1.0")) {
MessageService.ShowMessage("${res:XML.MainMenu.DebugMenu.Error.Net10NotSupported}");
} else {
if (DebugStarting != null)
DebugStarting(this, EventArgs.Empty);
UpdateBreakpointLines();
try {
// set the JIT flag for evaluating optimized code
Process.DebugMode = DebugModeFlag.Debug;
Process process = debugger.Attach(existingProcess);
CurrentProcess = CurrentDebugger.Attach(existingProcess);
debugger_ProcessStarted();
attached = true;
SelectProcess(process);
process.Modules.Added += process_Modules_Added;
CurrentProcess.ModuleLoaded += process_Modules_Added;
} catch (System.Exception e) {
// CORDBG_E_DEBUGGER_ALREADY_ATTACHED
if (e is COMException || e is UnauthorizedAccessException) {
@ -246,7 +242,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -246,7 +242,7 @@ namespace ICSharpCode.SharpDevelop.Services
public void Detach()
{
debugger.Detach();
CurrentDebugger.Detach();
}
public void StartWithoutDebugging(ProcessStartInfo processStartInfo)
@ -264,7 +260,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -264,7 +260,7 @@ namespace ICSharpCode.SharpDevelop.Services
StopAttachedProcessDialogResult result = ShowStopAttachedProcessDialog();
switch (result) {
case StopAttachedProcessDialogResult.Terminate:
debuggedProcess.Terminate();
CurrentProcess.Terminate();
attached = false;
break;
case StopAttachedProcessDialogResult.Detach:
@ -273,46 +269,32 @@ namespace ICSharpCode.SharpDevelop.Services @@ -273,46 +269,32 @@ namespace ICSharpCode.SharpDevelop.Services
break;
}
} else {
debuggedProcess.Terminate();
CurrentProcess.Terminate();
}
}
// ExecutionControl:
public void Break()
{
if (!IsDebugging) {
MessageService.ShowMessage(errorNotDebugging, "${res:XML.MainMenu.DebugMenu.Break}");
return;
if (CurrentProcess != null && CurrentProcess.IsRunning) {
CurrentProcess.Break();
}
if (!IsProcessRunning) {
MessageService.ShowMessage(errorProcessPaused, "${res:XML.MainMenu.DebugMenu.Break}");
return;
}
debuggedProcess.Break();
}
public void Continue()
{
if (!IsDebugging) {
MessageService.ShowMessage(errorNotDebugging, "${res:XML.MainMenu.DebugMenu.Continue}");
return;
}
if (IsProcessRunning) {
MessageService.ShowMessage(errorProcessRunning, "${res:XML.MainMenu.DebugMenu.Continue}");
return;
if (CurrentProcess != null && CurrentProcess.IsPaused) {
CurrentProcess.AsyncContinue();
}
debuggedProcess.AsyncContinue();
}
// Stepping:
// TODO - What is this?
Debugger.StackFrame GetStackFrame()
{
bool isMatch = false;
int line = -1;
int[] ilRange = null;
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
var frame = CurrentStackFrame;
int typeToken = frame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = frame.MethodInfo.MetadataToken;
@ -330,76 +312,22 @@ namespace ICSharpCode.SharpDevelop.Services @@ -330,76 +312,22 @@ namespace ICSharpCode.SharpDevelop.Services
public void StepInto()
{
if (!IsDebugging) {
MessageService.ShowMessage(errorNotDebugging, "${res:XML.MainMenu.DebugMenu.StepInto}");
return;
}
if (debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorProcessRunning, "${res:XML.MainMenu.DebugMenu.StepInto}");
return;
}
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepInto}");
} else {
if (!frame.HasSymbols) {
// get frame info from external code mappings
frame = GetStackFrame();
}
frame.AsyncStepInto();
if (CurrentStackFrame != null) {
CurrentStackFrame.AsyncStepInto();
}
}
public void StepOver()
{
if (!IsDebugging) {
MessageService.ShowMessage(errorNotDebugging, "${res:XML.MainMenu.DebugMenu.StepOver}");
return;
}
if (debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorProcessRunning, "${res:XML.MainMenu.DebugMenu.StepOver}");
return;
}
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepOver}");
} else {
if (!frame.HasSymbols) {
// get frame info from external code mappings
frame = GetStackFrame();
}
frame.AsyncStepOver();
if (CurrentStackFrame != null) {
CurrentStackFrame.AsyncStepOver();
}
}
public void StepOut()
{
if (!IsDebugging) {
MessageService.ShowMessage(errorNotDebugging, "${res:XML.MainMenu.DebugMenu.StepOut}");
return;
}
if (debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorProcessRunning, "${res:XML.MainMenu.DebugMenu.StepOut}");
return;
}
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepInto}");
} else {
if (!frame.HasSymbols) {
// get frame info from external code mappings
frame = GetStackFrame();
}
frame.AsyncStepOut();
if (CurrentStackFrame != null) {
CurrentStackFrame.AsyncStepOut();
}
}
@ -422,18 +350,11 @@ namespace ICSharpCode.SharpDevelop.Services @@ -422,18 +350,11 @@ namespace ICSharpCode.SharpDevelop.Services
/// </summary>
public Value GetValueFromName(string variableName)
{
if (!CanEvaluate) {
return null;
if (CurrentStackFrame != null) {
object data = debuggerDecompilerService.GetLocalVariableIndex(CurrentStackFrame.MethodInfo.DeclaringType.MetadataToken, CurrentStackFrame.MethodInfo.MetadataToken, variableName);
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, CurrentStackFrame, data);
}
var frame = debuggedProcess.GetCurrentExecutingFrame();
if (frame == null)
return null;
object data = debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken,
frame.MethodInfo.MetadataToken,
variableName);
// evaluate expression
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, frame, data);
return null;
}
/// <summary>
@ -442,10 +363,11 @@ namespace ICSharpCode.SharpDevelop.Services @@ -442,10 +363,11 @@ namespace ICSharpCode.SharpDevelop.Services
/// </summary>
public Expression GetExpression(string variableName)
{
if (!CanEvaluate) {
if (CurrentStackFrame != null) {
return ExpressionEvaluator.ParseExpression(variableName, SupportedLanguage.CSharp);
} else {
throw new GetValueException("Cannot evaluate now - debugged process is either null or running or has no selected stack frame");
}
return ExpressionEvaluator.ParseExpression(variableName, SupportedLanguage.CSharp);
}
public bool IsManaged(int processId)
@ -475,14 +397,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -475,14 +397,6 @@ namespace ICSharpCode.SharpDevelop.Services
}
}
bool CanEvaluate
{
get {
return debuggedProcess != null && !debuggedProcess.IsRunning &&
(debuggedProcess.SelectedStackFrame != null || debuggedProcess.SelectedThread.MostRecentStackFrame != null);
}
}
/// <summary>
/// Gets the tooltip control that shows the value of given variable.
/// Return null if no tooltip is available.
@ -491,52 +405,29 @@ namespace ICSharpCode.SharpDevelop.Services @@ -491,52 +405,29 @@ namespace ICSharpCode.SharpDevelop.Services
{
try {
var tooltipExpression = GetExpression(variableName);
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
ExpressionNode expressionNode = new ExpressionNode(null, image, variableName, tooltipExpression);
expressionNode.ImageName = imageName;
return new DebuggerTooltipControl(logicalPosition, expressionNode) { ShowPins = debuggedProcess.GetCurrentExecutingFrame().HasSymbols };
var valueNode = new ValueNode("Icons.16x16.Local", variableName, () => tooltipExpression.Evaluate());
return new DebuggerTooltipControl(new TreeNode[] { valueNode });
} catch (System.Exception ex) {
LoggingService.Error("Error on GetTooltipControl: " + ex.Message);
return null;
}
}
public ITreeNode GetNode(string variable, string currentImageName = null)
public Debugger.AddIn.TreeModel.TreeNode GetNode(string variable, string currentImageName = null)
{
try {
var expression = GetExpression(variable);
string imageName;
IImage image;
if (string.IsNullOrEmpty(currentImageName)) {
image = ExpressionNode.GetImageForLocalVariable(out imageName);
}
else {
image = new ResourceServiceImage(currentImageName);
imageName = currentImageName;
}
ExpressionNode expressionNode = new ExpressionNode(null, image, variable, expression);
expressionNode.ImageName = imageName;
return expressionNode;
return new ValueNode(currentImageName ?? "Icons.16x16.Local", variable, () => GetExpression(variable).Evaluate());
} catch (GetValueException) {
return null;
}
}
public bool CanSetInstructionPointer(string filename, int line, int column)
{
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.CanSetIP(filename, line, column);
return seg != null;
} else {
return false;
}
}
public bool SetInstructionPointer(string filename, int line, int column)
public bool SetInstructionPointer(string filename, int line, int column, bool dryRun)
{
if (CanSetInstructionPointer(filename, line, column)) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.SetIP(filename, line, column);
if (CurrentStackFrame != null) {
SourcecodeSegment seg = CurrentStackFrame.SetIP(filename, line, column, dryRun);
WindowsDebugger.RefreshPads();
JumpToCurrentLine();
return seg != null;
} else {
return false;
@ -554,23 +445,14 @@ namespace ICSharpCode.SharpDevelop.Services @@ -554,23 +445,14 @@ namespace ICSharpCode.SharpDevelop.Services
public void InitializeService()
{
if (useRemotingForThreadInterop) {
// This needs to be called before instance of NDebugger is created
string path = RemotingConfigurationHelpper.GetLoadedAssemblyPath("Debugger.Core.dll");
new RemotingConfigurationHelpper(path).Configure();
}
// get decompiler service
var items = AddInTree.BuildItems<IDebuggerDecompilerService>("/SharpDevelop/Services/DebuggerDecompilerService", null, false);
if (items.Count > 0)
debuggerDecompilerService = items[0];
// init NDebugger
debugger = new NDebugger();
debugger.Options = DebuggingOptions.Instance;
debugger.DebuggerTraceMessage += debugger_TraceMessage;
debugger.Processes.Added += debugger_ProcessStarted;
debugger.Processes.Removed += debugger_ProcessExited;
CurrentDebugger = new NDebugger();
CurrentDebugger.Options = DebuggingOptions.Instance;
DebuggerService.BreakPointAdded += delegate (object sender, BreakpointBookmarkEventArgs e) {
AddBreakpoint(e.BreakpointBookmark);
@ -580,18 +462,34 @@ namespace ICSharpCode.SharpDevelop.Services @@ -580,18 +462,34 @@ namespace ICSharpCode.SharpDevelop.Services
AddBreakpoint(b);
}
BookmarkManager.Removed += (sender, e) => {
BreakpointBookmark bm = e.Bookmark as BreakpointBookmark;
if (bm != null) {
Breakpoint bp = bm.InternalBreakpointObject as Breakpoint;
bp.IsEnabled = false;
}
};
if (Initialize != null) {
Initialize(this, null);
}
}
bool Compare(byte[] a, byte[] b)
void UpdateBreakpointLines()
{
if (a.Length != b.Length) return false;
for(int i = 0; i < a.Length; i++) {
if (a[i] != b[i]) return false;
foreach (BreakpointBookmark bookmark in BookmarkManager.Bookmarks.OfType<BreakpointBookmark>()) {
Breakpoint breakpoint = bookmark.InternalBreakpointObject as Breakpoint;
breakpoint.Line = bookmark.LineNumber;
breakpoint.Column = bookmark.ColumnNumber;
}
}
void UpdateBreakpointIcons()
{
foreach (BreakpointBookmark bookmark in BookmarkManager.Bookmarks.OfType<BreakpointBookmark>()) {
Breakpoint breakpoint = bookmark.InternalBreakpointObject as Breakpoint;
bookmark.IsHealthy = (CurrentProcess == null) || breakpoint.IsSet;
}
return true;
}
void AddBreakpoint(BreakpointBookmark bookmark)
@ -619,23 +517,13 @@ namespace ICSharpCode.SharpDevelop.Services @@ -619,23 +517,13 @@ namespace ICSharpCode.SharpDevelop.Services
int[] ilRanges;
int methodToken;
if (debuggerDecompilerService.GetILAndTokenByLineNumber(token, dbb.LineNumber, out ilRanges, out methodToken)) {
// create BP
breakpoint = new ILBreakpoint(
debugger,
memberReference.FullName,
dbb.LineNumber,
memberReference.MetadataToken.ToInt32(),
methodToken,
ilRanges[0],
dbb.IsEnabled);
debugger.Breakpoints.Add(breakpoint);
CurrentDebugger.AddILBreakpoint(memberReference.FullName, dbb.LineNumber, memberReference.MetadataToken.ToInt32(), methodToken, ilRanges[0], dbb.IsEnabled);
}
} catch (System.Exception ex) {
LoggingService.Error("Error on DecompiledBreakpointBookmark: " + ex.Message);
}
} else {
breakpoint = debugger.Breakpoints.Add(bookmark.FileName, null, bookmark.LineNumber, 0, bookmark.IsEnabled);
breakpoint = CurrentDebugger.AddBreakpoint(bookmark.FileName, bookmark.LineNumber, 0, bookmark.IsEnabled);
}
if (breakpoint == null) {
@ -643,100 +531,16 @@ namespace ICSharpCode.SharpDevelop.Services @@ -643,100 +531,16 @@ namespace ICSharpCode.SharpDevelop.Services
return;
}
MethodInvoker setBookmarkColor = delegate {
if (debugger.Processes.Count == 0) {
bookmark.IsHealthy = true;
bookmark.Tooltip = null;
} else if (!breakpoint.IsSet) {
bookmark.IsHealthy = false;
bookmark.Tooltip = "Breakpoint was not found in any loaded modules";
} else if (breakpoint.OriginalLocation == null || breakpoint.OriginalLocation.CheckSum == null) {
bookmark.IsHealthy = true;
bookmark.Tooltip = null;
} else {
if (!File.Exists(bookmark.FileName))
return;
byte[] fileMD5;
IEditable file = FileService.GetOpenFile(bookmark.FileName) as IEditable;
if (file != null) {
byte[] fileContent = Encoding.UTF8.GetBytesWithPreamble(file.Text);
fileMD5 = new MD5CryptoServiceProvider().ComputeHash(fileContent);
} else {
fileMD5 = new MD5CryptoServiceProvider().ComputeHash(File.ReadAllBytes(bookmark.FileName));
}
if (Compare(fileMD5, breakpoint.OriginalLocation.CheckSum)) {
bookmark.IsHealthy = true;
bookmark.Tooltip = null;
} else {
bookmark.IsHealthy = false;
bookmark.Tooltip = "Check sum or file does not match to the original";
}
}
};
// event handlers on bookmark and breakpoint don't need deregistration
bookmark.IsEnabledChanged += delegate {
breakpoint.Enabled = bookmark.IsEnabled;
};
breakpoint.Set += delegate { setBookmarkColor(); };
setBookmarkColor();
EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessStarted = (sender, e) => {
setBookmarkColor();
// User can change line number by inserting or deleting lines
breakpoint.Line = bookmark.LineNumber;
};
EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessExited = (sender, e) => {
setBookmarkColor();
};
EventHandler<BreakpointEventArgs> bp_debugger_BreakpointHit =
new EventHandler<BreakpointEventArgs>(
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;
bookmark.InternalBreakpointObject = breakpoint;
bookmark.IsHealthy = (CurrentProcess == null) || breakpoint.IsSet;
bookmark.IsEnabledChanged += delegate { breakpoint.IsEnabled = bookmark.IsEnabled; };
}
bool Evaluate(string code, string language)
{
try {
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true);
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedStackFrame);
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, CurrentStackFrame);
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
return (bool)val.PrimitiveValue;
@ -755,138 +559,124 @@ namespace ICSharpCode.SharpDevelop.Services @@ -755,138 +559,124 @@ namespace ICSharpCode.SharpDevelop.Services
DebuggerService.PrintDebugMessage(e.Message);
}
void debugger_TraceMessage(object sender, MessageEventArgs e)
{
LoggingService.Debug("Debugger: " + e.Message);
}
void debugger_ProcessStarted(object sender, CollectionItemEventArgs<Process> e)
void debugger_ProcessStarted()
{
if (debugger.Processes.Count == 1) {
if (DebugStarted != null) {
DebugStarted(this, EventArgs.Empty);
}
if (DebugStarted != null) {
DebugStarted(this, EventArgs.Empty);
}
e.Item.LogMessage += LogMessage;
}
void debugger_ProcessExited(object sender, CollectionItemEventArgs<Process> e)
{
if (debugger.Processes.Count == 0) {
if (DebugStopped != null) {
DebugStopped(this, e);
}
SelectProcess(null);
} else {
SelectProcess(debugger.Processes[0]);
}
}
public void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown -= debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed -= debuggedProcess_DebuggingResumed;
debuggedProcess.ModulesAdded -= debuggedProcess_ModulesAdded;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown += debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed += debuggedProcess_DebuggingResumed;
debuggedProcess.ModulesAdded += debuggedProcess_ModulesAdded;
debuggedProcess.BreakAtBeginning = BreakAtBeginning;
}
// reset
BreakAtBeginning = false;
JumpToCurrentLine();
OnProcessSelected(new ProcessEventArgs(process));
CurrentProcess.ModuleLoaded += (s, e) => UpdateBreakpointIcons();
CurrentProcess.ModuleLoaded += (s, e) => RefreshPads();
CurrentProcess.ModuleUnloaded += (s, e) => RefreshPads();
CurrentProcess.LogMessage += LogMessage;
CurrentProcess.Paused += debuggedProcess_DebuggingPaused;
CurrentProcess.Resumed += debuggedProcess_DebuggingResumed;
CurrentProcess.Exited += (s, e) => debugger_ProcessExited();
UpdateBreakpointIcons();
}
void debuggedProcess_ModulesAdded(object sender, ModuleEventArgs e)
void debugger_ProcessExited()
{
var currentModuleTypes = e.Module.GetNamesOfDefinedTypes();
foreach (var bookmark in DebuggerService.Breakpoints.OfType<DecompiledBreakpointBookmark>()) {
var breakpoint = debugger.Breakpoints.FirstOrDefault(
b => b is ILBreakpoint && b.Line == bookmark.LineNumber &&
((ILBreakpoint)b).MetadataToken == bookmark.MemberReference.MetadataToken.ToInt32());
if (breakpoint == null)
continue;
// set the breakpoint only if the module contains the type
if (!currentModuleTypes.Contains(breakpoint.TypeName))
continue;
breakpoint.SetBreakpoint(e.Module);
if (DebugStopped != null) {
DebugStopped(this, EventArgs.Empty);
}
CurrentProcess = null;
CurrentThread = null;
CurrentStackFrame = null;
UpdateBreakpointIcons();
RefreshPads();
}
void debuggedProcess_DebuggingPaused(object sender, ProcessEventArgs e)
void debuggedProcess_DebuggingPaused(object sender, DebuggerEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
using(new PrintTimes("Jump to current line")) {
JumpToCurrentLine();
CurrentProcess = e.Process;
CurrentThread = e.Thread;
CurrentStackFrame = CurrentThread != null ? CurrentThread.MostRecentUserStackFrame : null;
LoggingService.Info("Jump to current line");
JumpToCurrentLine();
if (e.ExceptionThrown != null) {
HandleException(e);
}
// TODO update tooltip
/*if (currentTooltipRow != null && currentTooltipRow.IsShown) {
using(new PrintTimes("Update tooltip")) {
try {
Utils.DoEvents(debuggedProcess);
AbstractNode updatedNode = ValueNode.Create(currentTooltipExpression);
currentTooltipRow.SetContentRecursive(updatedNode);
} catch (AbortedBecauseDebuggeeResumedException) {
}
foreach (Breakpoint breakpoint in e.BreakpointsHit) {
var bookmark = BookmarkManager.Bookmarks.OfType<BreakpointBookmark>().First(bm => bm.InternalBreakpointObject == breakpoint);
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
CurrentProcess.AsyncContinue();
break;
case BreakpointAction.Trace:
DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAt}") + "\n", bookmark.LineNumber, bookmark.FileName));
break;
}
}*/
}
RefreshPads();
}
void debuggedProcess_DebuggingResumed(object sender, ProcessEventArgs e)
void debuggedProcess_DebuggingResumed(object sender, DebuggerEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
DebuggerService.RemoveCurrentLineMarker();
CurrentThread = null;
CurrentStackFrame = null;
RefreshPads();
}
void debuggedProcess_ExceptionThrown(object sender, ExceptionEventArgs e)
void HandleException(DebuggerEventArgs e)
{
JumpToCurrentLine();
StringBuilder stacktraceBuilder = new StringBuilder();
if (e.IsUnhandled) {
if (e.ExceptionThrown.IsUnhandled) {
// Need to intercept now so that we can evaluate properties
if (e.Process.SelectedThread.InterceptException(e.Exception)) {
stacktraceBuilder.AppendLine(e.Exception.ToString());
if (e.Thread.InterceptException(e.ExceptionThrown)) {
stacktraceBuilder.AppendLine(e.ExceptionThrown.ToString());
string stackTrace;
try {
stackTrace = e.Exception.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.EndOfInnerException}"));
stackTrace = e.ExceptionThrown.GetStackTrace(e.Thread, StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.EndOfInnerException}"));
} catch (GetValueException) {
stackTrace = e.Process.SelectedThread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}"));
stackTrace = e.Thread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}"));
}
stacktraceBuilder.Append(stackTrace);
} else {
// For example, happens on stack overflow
stacktraceBuilder.AppendLine(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Error.CannotInterceptException}"));
stacktraceBuilder.AppendLine(e.Exception.ToString());
stacktraceBuilder.Append(e.Process.SelectedThread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}")));
stacktraceBuilder.AppendLine(e.ExceptionThrown.ToString());
stacktraceBuilder.Append(e.Thread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}")));
}
} else {
stacktraceBuilder.AppendLine(e.Exception.ToString());
stacktraceBuilder.Append(e.Process.SelectedThread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}")));
stacktraceBuilder.AppendLine(e.ExceptionThrown.ToString());
stacktraceBuilder.Append(e.Thread.GetStackTrace(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.Symbols}"), StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.LineFormat.NoSymbols}")));
}
string title = e.IsUnhandled ? StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Title.Unhandled}") : StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Title.Handled}");
string message = string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Message}"), e.Exception.Type);
Bitmap icon = WinFormsResourceService.GetBitmap(e.IsUnhandled ? "Icons.32x32.Error" : "Icons.32x32.Warning");
string title = e.ExceptionThrown.IsUnhandled ? StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Title.Unhandled}") : StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Title.Handled}");
string message = string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.ExceptionForm.Message}"), e.ExceptionThrown.Type);
Bitmap icon = WinFormsResourceService.GetBitmap(e.ExceptionThrown.IsUnhandled ? "Icons.32x32.Error" : "Icons.32x32.Warning");
DebuggeeExceptionForm.Show(debuggedProcess, title, message, stacktraceBuilder.ToString(), icon, e.IsUnhandled, e.Exception);
DebuggeeExceptionForm.Show(e.Process, title, message, stacktraceBuilder.ToString(), icon, e.ExceptionThrown.IsUnhandled, e.ExceptionThrown);
}
public bool BreakAndInterceptHandledException(Debugger.Exception exception)
{
if (!debuggedProcess.SelectedThread.InterceptException(exception)) {
if (!CurrentThread.InterceptException(exception)) {
MessageService.ShowError("${res:MainWindow.Windows.Debug.ExceptionForm.Error.CannotInterceptHandledException}");
return false;
}
@ -896,35 +686,35 @@ namespace ICSharpCode.SharpDevelop.Services @@ -896,35 +686,35 @@ namespace ICSharpCode.SharpDevelop.Services
public void JumpToCurrentLine()
{
if (debuggedProcess == null || debuggedProcess.SelectedThread == null)
if (CurrentThread == null)
return;
WorkbenchSingleton.MainWindow.Activate();
if (debuggedProcess.IsSelectedFrameForced()) {
if (debuggedProcess.SelectedStackFrame != null && debuggedProcess.SelectedStackFrame.HasSymbols) {
// if (debuggedProcess.IsSelectedFrameForced()) {
if (CurrentThread != null && CurrentStackFrame.HasSymbols) {
JumpToSourceCode();
} else {
JumpToDecompiledCode(debuggedProcess.SelectedStackFrame);
JumpToDecompiledCode(CurrentStackFrame);
}
} else {
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
// other pause reasons
if (frame != null && frame.HasSymbols) {
JumpToSourceCode();
} else {
// use most recent stack frame because we don't have the symbols
JumpToDecompiledCode(debuggedProcess.SelectedThread.MostRecentStackFrame);
}
}
// } else {
// var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
// // other pause reasons
// if (frame != null && frame.HasSymbols) {
// JumpToSourceCode();
// } else {
// // use most recent stack frame because we don't have the symbols
// JumpToDecompiledCode(debuggedProcess.SelectedThread.MostRecentStackFrame);
// }
// }
}
void JumpToSourceCode()
{
if (debuggedProcess == null || debuggedProcess.SelectedThread == null)
if (CurrentProcess == null || CurrentStackFrame == null)
return;
SourcecodeSegment nextStatement = debuggedProcess.NextStatement;
SourcecodeSegment nextStatement = CurrentStackFrame.NextStatement;
if (nextStatement != null) {
DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
@ -944,7 +734,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -944,7 +734,7 @@ namespace ICSharpCode.SharpDevelop.Services
}
// check for options - if these options are enabled, debugging decompiled code should not continue
if (!debuggedProcess.Options.DecompileCodeWithoutSymbols) {
if (!CurrentProcess.Options.DecompileCodeWithoutSymbols) {
LoggingService.Info("Decompiled code debugging is disabled!");
return;
}
@ -982,14 +772,14 @@ namespace ICSharpCode.SharpDevelop.Services @@ -982,14 +772,14 @@ namespace ICSharpCode.SharpDevelop.Services
return (StopAttachedProcessDialogResult)MessageService.ShowCustomDialog(caption, message, (int)StopAttachedProcessDialogResult.Detach, (int)StopAttachedProcessDialogResult.Cancel, buttonLabels);
}
void process_Modules_Added(object sender, CollectionItemEventArgs<Module> e)
void process_Modules_Added(object sender, ModuleEventArgs e)
{
if (ProjectService.OpenSolution == null)
return;
ProjectService.OpenSolution.Projects
.Where(p => e.Item.Name.IndexOf(p.Name) >= 0)
.ForEach(p => e.Item.LoadSymbolsFromDisk(new []{ Path.GetDirectoryName(p.OutputAssemblyFullPath) }));
.Where(p => e.Module.Name.IndexOf(p.Name) >= 0)
.ForEach(p => e.Module.LoadSymbolsFromDisk(new []{ Path.GetDirectoryName(p.OutputAssemblyFullPath) }));
}
}
}

102
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs

@ -1,102 +0,0 @@ @@ -1,102 +0,0 @@
// 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.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Popup containing <see cref="DebuggerTooltipControl"></see>.
/// </summary>
public class DebuggerPopup : Popup
{
internal DebuggerTooltipControl innerControl;
public DebuggerPopup(DebuggerTooltipControl parentControl, Location logicalPosition, bool showPins = true)
{
this.innerControl = new DebuggerTooltipControl(parentControl, logicalPosition) { ShowPins = showPins };
this.innerControl.containingPopup = this;
this.Child = this.innerControl;
this.IsLeaf = false;
//this.KeyDown += new KeyEventHandler(DebuggerPopup_KeyDown);
//this.innerControl.Focusable = true;
//Keyboard.Focus(this.innerControl);
//this.AllowsTransparency = true;
//this.PopupAnimation = PopupAnimation.Slide;
}
// attempt to propagate shortcuts to main windows when Popup is focusable (needed for keyboard scrolling + editing)
/*void DebuggerPopup_KeyDown(object sender, KeyEventArgs e)
{
LoggingService.Debug("Unhandled popup key down: " + e.Key);
RaiseEventPair(WorkbenchSingleton.MainWindow, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
// copied from CompletionWindowBase
static bool RaiseEventPair(UIElement target, RoutedEvent previewEvent, RoutedEvent @event, RoutedEventArgs args)
{
if (target == null)
throw new ArgumentNullException("target");
if (previewEvent == null)
throw new ArgumentNullException("previewEvent");
if (@event == null)
throw new ArgumentNullException("event");
if (args == null)
throw new ArgumentNullException("args");
args.RoutedEvent = previewEvent;
target.RaiseEvent(args);
args.RoutedEvent = @event;
target.RaiseEvent(args);
return args.Handled;
}*/
public IEnumerable<ITreeNode> ItemsSource
{
get { return this.innerControl.ItemsSource; }
set { this.innerControl.SetItemsSource(value); }
}
private bool isLeaf;
public bool IsLeaf
{
get { return isLeaf; }
set
{
isLeaf = value;
// leaf popup closes on lost focus
this.StaysOpen = !isLeaf;
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
if (isLeaf) {
this.innerControl.CloseOnLostFocus();
}
}
public void Open()
{
this.IsOpen = true;
}
public void CloseSelfAndChildren()
{
this.innerControl.CloseChildPopups();
this.IsOpen = false;
}
}
}

338
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml

@ -1,29 +1,123 @@ @@ -1,29 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
<Popup
x:Class="Debugger.AddIn.Tooltips.DebuggerTooltipControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:debugging="clr-namespace:Debugger.AddIn.Tooltips" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:localControls="clr-namespace:Debugger.AddIn.Tooltips"
Background="Transparent">
<UserControl.Resources>
xmlns:debugging="clr-namespace:Debugger.AddIn.Tooltips"
AllowsTransparency="True"
>
<Popup.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="VisualizerPicker.xaml" />
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
<ResourceDictionary Source="VisualizerPicker.xaml" />
</ResourceDictionary.MergedDictionaries>
<LinearGradientBrush x:Key="OrangeBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="1" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="OrangePressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="0" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="1" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverPressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="0" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<ControlTemplate x:Key="CloseButtonTemplate" TargetType="Button">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="2,2,0,0" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas>
<Line X1="3.5" X2="10.5" Y1="3.5" Y2="10.5" Stroke="Black" StrokeThickness="2"/>
<Line X1="3.5" X2="10.5" Y1="10.5" Y2="3.5" Stroke="Black" StrokeThickness="2"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="PinButtonTemplate" TargetType="Button">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="3" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas Name="TheCanvas">
<Line X1="4" X2="10" Y1="2" Y2="2" Stroke="Black" StrokeThickness="1"/>
<Line X1="9" X2="9" Y1="2" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Line X1="2" X2="12" Y1="8" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Rectangle Fill="Black" Width="2" Height="5" Canvas.Left="4" Canvas.Top="3"/>
<Line X1="7" X2="7" Y1="9" Y2="12" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<SolidColorBrush x:Key="MouseOverPinBrush" Color="Black" />
<Style TargetType="{x:Type TextBox}" x:Key="TextStyle">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Khmer UI" />
<Setter Property="FontSize" Value="12" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border Name="Border" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
<ScrollViewer Margin="0" Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PinThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<StackPanel x:Name="Container"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel
Orientation="Vertical">
<RepeatButton
Name="btnUp"
Focusable="False"
Style="{StaticResource upButtonStyle}"
Content="^"
Click="BtnUp_Click"></RepeatButton>
</Popup.Resources>
<StackPanel Orientation="Horizontal">
<DataGrid
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Disabled"
@ -32,7 +126,6 @@ @@ -32,7 +126,6 @@
MaxHeight="202"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding}"
Name="dataGrid"
AutoGenerateColumns="False"
CanUserAddRows="False"
@ -40,90 +133,89 @@ @@ -40,90 +133,89 @@
BorderBrush="Gray"
BorderThickness="1">
<DataGrid.Background>
<!-- Control backgound -->
<LinearGradientBrush
StartPoint="0,-0.03"
EndPoint="0,1">
<GradientStop
Color="White" />
<GradientStop
Color="#FFFAFCFE"
Offset="0.983" />
<GradientStop
Color="#FFECF7FC"
Offset="0.07" />
<GradientStop
Color="#FFEEF7FA"
Offset="0.436" />
<LinearGradientBrush StartPoint="0,-0.03" EndPoint="0,1">
<GradientStop Color="White"/>
<GradientStop Color="#FFFAFCFE" Offset="0.983"/>
<GradientStop Color="#FFECF7FC" Offset="0.07"/>
<GradientStop Color="#FFEEF7FA" Offset="0.436"/>
</LinearGradientBrush>
</DataGrid.Background>
<DataGrid.RowStyle>
<Style
TargetType="{x:Type DataGridRow}">
<Setter
Property="Background"
Value="Transparent"></Setter>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="Transparent"></Setter>
<Style.Triggers>
<Trigger
Property="IsMouseOver"
Value="True">
<Setter
Property="Background"
Value="#FFE2F6FE" />
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FFE2F6FE" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style
TargetType="{x:Type DataGridCell}">
<Setter
Property="Focusable"
Value="false" />
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Focusable" Value="false" />
<!-- Focusable=true blocks shortcuts if cell is focused -->
<Setter
Property="BorderThickness"
Value="0" />
<Setter Property="BorderThickness" Value="0" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<Trigger Property="IsSelected" Value="True">
<!-- disable selection highlight -->
<Setter
Property="Foreground"
Value="Black" />
<Setter
Property="Background"
Value="{x:Null}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<!-- "Plus" expander -->
<DataGridTemplateColumn>
<!-- "Plus" expander -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid
Background="White">
<StackPanel
VerticalAlignment="Center">
<Grid Background="White">
<StackPanel VerticalAlignment="Center">
<ToggleButton
x:Name="btnExpander"
Style="{StaticResource ExpandCollapseToggleStyle}"
Click="btnExpander_Click"
Click="Expand_Click"
Padding="0"
Margin="0" />
Margin="0"
Focusable="False"
Width="19"
Height="13"
>
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Width="19" Height="13" Background="Transparent">
<Border Width="9"
Height="9"
BorderThickness="1"
BorderBrush="#FF7898B5"
CornerRadius="1"
SnapsToDevicePixels="true">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" Offset=".2"/>
<GradientStop Color="#FFC0B7A6" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path x:Name="ExpandPath"
Margin="1,1,1,1"
Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath" Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasChildNodes}"
Value="False">
<Setter
TargetName="btnExpander"
Property="Visibility"
Value="Collapsed" />
<DataTrigger Binding="{Binding HasChildren}" Value="False">
<Setter TargetName="btnExpander" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
@ -133,24 +225,16 @@ @@ -133,24 +225,16 @@
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image
Source="{Binding ImageSource}"></Image>
<Image Source="{Binding Image.ImageSource}"></Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Name">
<!-- Name -->
<!-- Name -->
<DataGridTemplateColumn MinWidth="20" Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
BorderBrush="#FFDDDDDD"
BorderThickness="0 0 1 0">
<TextBlock
Style="{StaticResource TextBlockStyle}"
Text="{Binding Path=Name, Mode=OneWay}"
VerticalAlignment="Top"></TextBlock>
<Border BorderBrush="#FFDDDDDD" BorderThickness="0 0 1 0">
<TextBlock Margin="6 0" Text="{Binding Path=Name, Mode=OneWay}" VerticalAlignment="Top"></TextBlock>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
@ -159,82 +243,48 @@ @@ -159,82 +243,48 @@
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<debugging:VisualizerPicker
Focusable="False"
x:Name="visPicker"
ItemsSource="{Binding Path=VisualizerCommands, Mode=OneWay}"
Margin="4 0 0 0"></debugging:VisualizerPicker>
<debugging:VisualizerPicker Focusable="False" x:Name="visPicker" ItemsSource="{Binding Path=VisualizerCommands, Mode=OneWay}" Margin="4 0 0 0"></debugging:VisualizerPicker>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasVisualizerCommands}"
Value="False">
<Setter
TargetName="visPicker"
Property="Visibility"
Value="Collapsed" />
<DataTrigger Binding="{Binding HasVisualizerCommands}" Value="False">
<Setter TargetName="visPicker" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Text">
<!-- Text (value) -->
<!-- Text (value) -->
<DataGridTemplateColumn MinWidth="20" Header="Text">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox
Style="{StaticResource TextStyle}"
IsEnabled="{Binding CanSetText}"
KeyUp="TextBox_KeyUp"
IsEnabled="{Binding CanSetValue}"
ContextMenuService.ShowOnDisabled="True"
Text="{Binding Path=Text}">
Text="{Binding Value}"
>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{core:Localize XML.MainMenu.EditMenu.Copy}" DataContext="{Binding}" Click="CopyMenuItemClick">
<!-- <MenuItem Header="{core:Localize XML.MainMenu.EditMenu.Copy}" DataContext="{Binding}" Click="CopyMenuItemClick">
<MenuItem.Icon>
<Image Source="{core:GetBitmap Icons.16x16.CopyIcon}" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>-->
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<!-- Pin -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton
IsChecked="{Binding IsPinned}"
DataContext="{Binding}"
Visibility="Collapsed"
Name="PinButton"
VerticalAlignment="Center"
Checked="PinButton_Checked"
Unchecked="PinButton_Unchecked"
Template="{StaticResource PinTooltipButtonTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}}"
Value="True">
<Setter
TargetName="PinButton"
Property="Visibility"
Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<RepeatButton
Name="btnDown"
Focusable="False"
Style="{StaticResource downButtonStyle}"
Content="v"
Click="BtnDown_Click"></RepeatButton>
<!-- <StackPanel Opacity="0.2" Name="SideButtons" Margin="3">
<Button
Name="CloseButton"
Click="CloseButton_Click"
Template="{StaticResource CloseButtonTemplate}" />
<Button
Name="UnpinButton"
Template="{StaticResource PinButtonTemplate}" />
</StackPanel>-->
</StackPanel>
</UserControl>
</Popup>

440
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs

@ -3,425 +3,117 @@ @@ -3,425 +3,117 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Default Control used as content of SharpDevelop debugger tooltips.
/// </summary>
public partial class DebuggerTooltipControl : UserControl, ITooltip
public partial class DebuggerTooltipControl : Popup, ITooltip
{
private const double ChildPopupOpenXOffet = 16;
private const double ChildPopupOpenYOffet = 15;
private const int InitialItemsCount = 12;
private const int VisibleItemsCount = 11;
static Point ChildPopupOffset = new Point(16, 15);
private bool showPins = true;
private LazyItemsControl<ITreeNode> lazyGrid;
private IEnumerable<ITreeNode> itemsSource;
readonly Location logicalPosition;
public DebuggerTooltipControl ChildTooltip { get; private set; }
public IEnumerable<TreeNode> TreeNodes { get; set; }
public DebuggerTooltipControl(Location logicalPosition)
public DebuggerTooltipControl(IEnumerable<TreeNode> treeNodes)
{
this.logicalPosition = logicalPosition;
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
public DebuggerTooltipControl(Location logicalPosition, ITreeNode node)
: this(logicalPosition, new ITreeNode[] { node })
{
this.TreeNodes = treeNodes;
this.dataGrid.ItemsSource = treeNodes;
}
public DebuggerTooltipControl(Location logicalPosition, IEnumerable<ITreeNode> nodes)
: this(logicalPosition)
{
this.itemsSource = nodes;
}
public DebuggerTooltipControl(DebuggerTooltipControl parentControl, Location logicalPosition)
: this(logicalPosition)
{
this.parentControl = parentControl;
// Only the leaf of the tooltip has this set to false
// Therefore it will automatically close if something else gets focus
this.StaysOpen = false;
this.Placement = PlacementMode.Absolute;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (!showPins) {
dataGrid.Columns[5].Visibility = Visibility.Collapsed;
}
SetItemsSource(this.itemsSource);
}
public event RoutedEventHandler Closed;
protected void OnClosed()
private void Expand_Click(object sender, RoutedEventArgs e)
{
if (this.Closed != null) {
this.Closed(this, new RoutedEventArgs());
}
}
public bool ShowPins {
get { return showPins; }
set { showPins = value; }
}
public IEnumerable<ITreeNode> ItemsSource {
get { return this.itemsSource; }
}
public void SetItemsSource(IEnumerable<ITreeNode> value) {
this.itemsSource = value;
this.lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount);
// HACK for updating the pins in tooltip
var observable = new List<ITreeNode>();
this.itemsSource.ForEach(item => observable.Add(item));
// verify if at the line of the root there's a pin bookmark
ITextEditor editor;
var viewContent = WorkbenchSingleton.Workbench.ActiveViewContent;
ITextEditorProvider provider = viewContent as ITextEditorProvider;
if (provider != null) {
editor = provider.TextEditor;
} else {
editor = viewContent.GetService(typeof(ITextEditor)) as ITextEditor;
}
var clickedButton = (ToggleButton)e.OriginalSource;
var clickedNode = (TreeNode)clickedButton.DataContext;
if (editor != null) {
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.Location.Line == logicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (clickedButton.IsChecked == true && clickedNode.GetChildren != null) {
Point popupPos = clickedButton.PointToScreen(ChildPopupOffset).TransformFromDevice(clickedButton);
this.ChildTooltip = new DebuggerTooltipControl(clickedNode.GetChildren().ToList()) {
// We can not use placement target otherwise we would get too deep logical tree
Placement = PlacementMode.Absolute,
HorizontalOffset = popupPos.X,
VerticalOffset = popupPos.Y,
};
if (pin != null) {
observable.ForEach(item => { // TODO: find a way not to use "observable"
if (pin.ContainsNode(item))
item.IsPinned = true;
});
}
}
var source = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = source;
this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
if (this.lazyGrid.ItemsSourceTotalCount != null) {
// hide up/down buttons if too few items
btnUp.Visibility = btnDown.Visibility =
this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible;
// The child is now tracking the focus
this.StaysOpen = true;
this.ChildTooltip.StaysOpen = false;
this.ChildTooltip.Closed += delegate {
// The null will have the effect of ignoring the next click
clickedButton.IsChecked = clickedButton.IsMouseOver ? (bool?)null : false;
// Either keep closing or make us the new leaf
if (this.IsMouseOver) {
this.StaysOpen = false;
} else {
this.IsOpen = false;
}
};
this.ChildTooltip.IsOpen = true;
}
}
//public Location LogicalPosition { get; set; }
/// <inheritdoc/>
public bool ShowAsPopup
{
get
{
return true;
}
}
/// <inheritdoc/>
public bool Close(bool mouseClick)
{
if (mouseClick || (!mouseClick && !isChildExpanded)) {
CloseChildPopups();
return true;
} else {
return false;
}
}
private DebuggerPopup childPopup { get; set; }
private DebuggerTooltipControl parentControl { get; set; }
internal DebuggerPopup containingPopup { get; set; }
bool isChildExpanded
{
get
{
return this.childPopup != null && this.childPopup.IsOpen;
}
}
private ToggleButton expandedButton;
/// <summary>
/// Closes the child popup of this control, if it exists.
/// </summary>
public void CloseChildPopups()
{
if (this.expandedButton != null) {
this.expandedButton.IsChecked = false;
this.expandedButton = null;
// nice simple example of indirect recursion
this.childPopup.CloseSelfAndChildren();
}
}
public void CloseOnLostFocus()
{
// when we close, parent becomes leaf
if (this.containingPopup != null) {
this.containingPopup.IsLeaf = true;
}
if (!this.IsMouseOver) {
if (this.containingPopup != null) {
this.containingPopup.IsOpen = false;
this.containingPopup.IsLeaf = false;
}
if (this.parentControl != null) {
this.parentControl.CloseOnLostFocus();
}
OnClosed();
} else {
// leaf closed because of click inside this control - stop the closing chain
if (this.expandedButton != null && !this.expandedButton.IsMouseOver) {
this.expandedButton.IsChecked = false;
this.expandedButton = null;
}
bool ITooltip.CloseOnHoverEnd {
get {
return this.ChildTooltip == null;
}
}
private void btnExpander_Click(object sender, RoutedEventArgs e)
protected override void OnClosed(EventArgs e)
{
var clickedButton = (ToggleButton)e.OriginalSource;
var clickedNode = (ITreeNode)clickedButton.DataContext;
// use device independent units, because child popup Left/Top are in independent units
Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton);
if (clickedButton.IsChecked.GetValueOrDefault(false)) {
CloseChildPopups();
this.expandedButton = clickedButton;
// open child Popup
if (this.childPopup == null) {
this.childPopup = new DebuggerPopup(this, logicalPosition, showPins);
this.childPopup.Placement = PlacementMode.Absolute;
}
if (this.containingPopup != null) {
this.containingPopup.IsLeaf = false;
}
this.childPopup.IsLeaf = true;
this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet;
this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet;
if (clickedNode.ChildNodes != null) {
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
}
} else {
CloseChildPopups();
// Closing the popup does not normally cause LostFocus on the textbox so we have to update it manually
TextBox textBox = FocusManager.GetFocusedElement(this) as TextBox;
if (textBox != null) {
BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart;
btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd;
}
void BtnUp_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollUp(1);
}
void BtnDown_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollDown(1);
}
#region Edit value in tooltip
void TextBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape) {
dataGrid.Focus();
return;
}
base.OnClosed(e);
if (e.Key == Key.Enter) {
dataGrid.Focus();
// set new value
var textBox = (TextBox)e.OriginalSource;
var newValue = textBox.Text;
var node = ((FrameworkElement)sender).DataContext as ITreeNode;
SaveNewValue(node, textBox.Text);
}
}
void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)e.OriginalSource;
var newValue = textBox.Text;
var node = ((FrameworkElement)sender).DataContext as ITreeNode;
SaveNewValue(node, textBox.Text);
}
void SaveNewValue(ITreeNode node, string newValue)
{
if(node != null && node.SetText(newValue)) {
// show adorner
var adornerLayer = AdornerLayer.GetAdornerLayer(dataGrid);
var adorners = adornerLayer.GetAdorners(dataGrid);
if (adorners != null && adorners.Length != 0)
adornerLayer.Remove(adorners[0]);
SavedAdorner adorner = new SavedAdorner(dataGrid);
adornerLayer.Add(adorner);
}
}
#endregion
#region Pining checked/unchecked
void PinButton_Checked(object sender, RoutedEventArgs e)
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor == null) return;
var node = (ITreeNode)(((ToggleButton)(e.OriginalSource)).DataContext);
if (!string.IsNullOrEmpty(editor.FileName)) {
// verify if at the line of the root there's a pin bookmark
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.LineNumber == logicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin == null) {
pin = new PinBookmark(editor.FileName, logicalPosition);
// show pinned DebuggerPopup
if (pin.Popup == null) {
pin.Popup = new PinDebuggerControl();
pin.Popup.Mark = pin;
Rect rect = new Rect(this.DesiredSize);
var point = this.PointToScreen(rect.TopRight);
pin.Popup.Location = new Point { X = 500, Y = point.Y - 150 };
pin.Nodes.Add(node);
pin.Popup.ItemsSource = pin.Nodes;
}
// do actions
pin.Popup.Open();
BookmarkManager.AddMark(pin);
}
else
{
if (!pin.ContainsNode(node)) {
pin.Nodes.Add(node);
pin.Popup.ItemsSource = pin.Nodes;
}
}
}
}
void PinButton_Unchecked(object sender, RoutedEventArgs e)
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor == null) return;
if (!string.IsNullOrEmpty(editor.FileName)) {
// remove from pinned DebuggerPopup
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.LineNumber == logicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin == null) return;
ToggleButton button = (ToggleButton)e.OriginalSource;
pin.RemoveNode((ITreeNode)button.DataContext);
pin.Popup.ItemsSource = pin.Nodes;
// remove if no more data pins are available
if (pin.Nodes.Count == 0) {
pin.Popup.Close();
BookmarkManager.RemoveMark(pin);
}
if (this.ChildTooltip != null) {
this.ChildTooltip.IsOpen = false;
}
}
void CopyMenuItemClick(object sender, RoutedEventArgs e)
{
ExpressionNode node = ((MenuItem)sender).DataContext as ExpressionNode;
ValueNode node = ((MenuItem)sender).DataContext as ValueNode;
if (node != null) {
Clipboard.SetText(node.FullText);
}
}
#endregion
#region Saved Adorner
class SavedAdorner : Adorner
/*
void AnimateCloseControl(bool show)
{
public SavedAdorner(UIElement adornedElement) : base(adornedElement)
{
Loaded += delegate { Show(); };
}
DoubleAnimation animation = new DoubleAnimation();
animation.From = show ? 0 : 1;
animation.To = show ? 1 : 0;
animation.BeginTime = new TimeSpan(0, 0, show ? 0 : 1);
animation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
animation.SetValue(Storyboard.TargetProperty, this.PinCloseControl);
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty));
protected override void OnRender(DrawingContext drawingContext)
{
Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
// Some arbitrary drawing implements.
var formatedText = new FormattedText(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Debugging.SavedString}"),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial"),
FontStyles.Normal,
FontWeights.Black,
FontStretches.Expanded),
8d,
Brushes.Black);
drawingContext.DrawText(formatedText,
new Point(adornedElementRect.TopRight.X - formatedText.Width - 2,
adornedElementRect.TopRight.Y));
}
Storyboard board = new Storyboard();
board.Children.Add(animation);
private void Show()
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = 1;
animation.To = 0;
animation.Duration = new Duration(TimeSpan.FromSeconds(2));
animation.SetValue(Storyboard.TargetProperty, this);
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty));
Storyboard board = new Storyboard();
board.Children.Add(animation);
board.Begin(this);
}
board.Begin(this);
}
#endregion
*/
}
}

113
src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs

@ -1,113 +0,0 @@ @@ -1,113 +0,0 @@
// 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.Windows.Controls;
using ICSharpCode.SharpDevelop;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// ItemsControl wrapper that takes VirtualizingIEnumerable as source,
/// and adds additional items from the source to underlying ItemsControl when scrolled to bottom.
/// </summary>
public class LazyItemsControl<T>
{
private ItemsControl itemsControl;
private int initialItemsCount;
/// <summary>
/// Creates new instance of LazyItemsControl.
/// </summary>
/// <param name="wrappedItemsControl">ItemsControl to wrap and add items to it when scrolled to bottom.</param>
/// <param name="initialItemsCount">Number of items to be initially displayed in wrapped ItemsControl.</param>
public LazyItemsControl(ItemsControl wrappedItemsControl, int initialItemsCount)
{
if (wrappedItemsControl == null)
throw new ArgumentNullException("wrappedItemsControl");
this.initialItemsCount = initialItemsCount;
this.itemsControl = wrappedItemsControl;
this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
}
private ScrollViewer scrollViewerCached;
public ScrollViewer ScrollViewer
{
get
{
if (this.scrollViewerCached == null)
this.scrollViewerCached = this.itemsControl.GetScrollViewer();
return this.scrollViewerCached;
}
}
public bool IsScrolledToStart
{
get
{
if (ScrollViewer == null) // Visual tree not initialized yet
return false;
return ScrollViewer.VerticalOffset == 0;
}
}
public bool IsScrolledToEnd
{
get
{
if (itemsSourceTotalCount == null) {
// not scrolled to end of IEnumerable yet
return false;
}
// already scrolled to end of IEnumerable
int totalItems = itemsSourceTotalCount.Value;
return (ScrollViewer.VerticalOffset >= totalItems - ScrollViewer.ViewportHeight);
}
}
private int? itemsSourceTotalCount = null;
/// <summary> Items count of underlying IEnumerable. Null until scrolled to the end of IEnumerable. </summary>
public int? ItemsSourceTotalCount
{
get
{
return this.itemsSourceTotalCount;
}
}
private VirtualizingIEnumerable<T> itemsSource;
/// <summary> The collection that underlying ItemsControl sees. </summary>
public VirtualizingIEnumerable<T> ItemsSource
{
get { return itemsSource; }
set
{
this.itemsSource = value;
addNextItems(this.itemsSource, initialItemsCount);
this.itemsControl.ItemsSource = value;
}
}
private void addNextItems(VirtualizingIEnumerable<T> sourceToAdd, int nItems)
{
sourceToAdd.AddNextItems(nItems);
if (!sourceToAdd.HasNext) {
// all items from IEnumerable have been added
this.itemsSourceTotalCount = sourceToAdd.Count;
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
if (e.VerticalChange > 0) {
// scrolled to bottom
if (e.VerticalOffset >= this.itemsSource.Count - e.ViewportHeight) {
addNextItems(this.itemsSource, (int)e.VerticalChange);
}
}
}
}
}

29
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml

@ -1,29 +0,0 @@ @@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
Background="Transparent"
x:Class="Debugger.AddIn.Tooltips.PinCloseControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<Button
Name="CloseButton"
Click="CloseButton_Click"
Template="{StaticResource CloseButtonTemplate}" />
<ToggleButton
Name="UnpinButton"
Checked="UnpinButton_Checked"
Unchecked="UnpinButton_Unchecked"
Template="{StaticResource PinButtonTemplate}" />
<ToggleButton
Name="CommentButton"
Checked="CommentButton_Checked"
Unchecked="CommentButton_Unchecked"
Template="{StaticResource CommentButtonTemplate}" />
</StackPanel>
</UserControl>

74
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml.cs

@ -1,74 +0,0 @@ @@ -1,74 +0,0 @@
// 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.Windows;
using System.Windows.Controls;
namespace Debugger.AddIn.Tooltips
{
public class ShowingCommentEventArgs : EventArgs
{
public bool ShowComment { get; private set; }
public ShowingCommentEventArgs(bool showComment)
{
ShowComment = showComment;
}
}
public partial class PinCloseControl : UserControl
{
public event EventHandler Closed;
public event EventHandler PinningChanged;
public event EventHandler<ShowingCommentEventArgs> ShowingComment;
public PinCloseControl()
{
InitializeComponent();
}
public bool IsChecked {
get {
return UnpinButton.IsChecked.GetValueOrDefault(false);
}
}
void CloseButton_Click(object sender, RoutedEventArgs e)
{
var handler = Closed;
if (handler != null)
handler(this, EventArgs.Empty);
}
void CommentButton_Checked(object sender, RoutedEventArgs e)
{
var handler = ShowingComment;
if (handler != null)
handler(this, new ShowingCommentEventArgs(true));
}
void CommentButton_Unchecked(object sender, RoutedEventArgs e)
{
var handler = ShowingComment;
if (handler != null)
handler(this, new ShowingCommentEventArgs(false));
}
void UnpinButton_Checked(object sender, RoutedEventArgs e)
{
var handler = PinningChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
void UnpinButton_Unchecked(object sender, RoutedEventArgs e)
{
var handler = PinningChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
}

363
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinControlsDictionary.xaml

@ -1,363 +0,0 @@ @@ -1,363 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Debugger.AddIn.Tooltips"
xmlns:core="http://icsharpcode.net/sharpdevelop/core"
>
<LinearGradientBrush x:Key="OrangeBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="1" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="OrangePressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="0" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="1" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverPressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="0" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<ControlTemplate x:Key="CloseButtonTemplate" TargetType="Button">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="2,2,0,0" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas>
<Line X1="3.5" X2="10.5" Y1="3.5" Y2="10.5" Stroke="Black" StrokeThickness="2"/>
<Line X1="3.5" X2="10.5" Y1="10.5" Y2="3.5" Stroke="Black" StrokeThickness="2"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<TransformGroup x:Key="Rotate">
<RotateTransform Angle="270" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="RotateUnpin">
<RotateTransform Angle="270" CenterX="7" CenterY="7"/>
<RotateTransform Angle="-90" CenterX="7" CenterY="7"/>
<ScaleTransform ScaleY="-1" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="RotatePin">
<RotateTransform Angle="-90" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="FlipComment">
<ScaleTransform CenterX="7" CenterY="7" ScaleY="-1"/>
</TransformGroup>
<ControlTemplate x:Key="PinButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="0" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas Name="TheCanvas">
<Line X1="4" X2="10" Y1="2" Y2="2" Stroke="Black" StrokeThickness="1"/>
<Line X1="9" X2="9" Y1="2" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Line X1="2" X2="12" Y1="8" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Rectangle Fill="Black" Width="2" Height="5" Canvas.Left="4" Canvas.Top="3"/>
<Line X1="7" X2="7" Y1="9" Y2="12" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotatePin}"/>
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotatePin}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="CommentButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="0,0,2,2" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas Name="TheCanvas">
<Line X1="3" Y1="3" X2="7" Y2="7.5" Stroke="Black" StrokeThickness="1"/>
<Line X1="7" Y1="7.4" X2="11" Y2="3" Stroke="Black" StrokeThickness="1"/>
<Line X1="3" Y1="7.5" X2="7" Y2="12" Stroke="Black" StrokeThickness="1"/>
<Line X1="7" Y1="12" X2="11" Y2="7.5" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource FlipComment}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<SolidColorBrush x:Key="MouseOverPinBrush" Color="Black" />
<ControlTemplate x:Key="PinTooltipButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="2" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
<Canvas RenderTransform="{StaticResource Rotate}" Name="TheCanvas">
<Line X1="4" X2="10" Y1="2" Y2="2" Stroke="Silver" StrokeThickness="1" Name="Line1"/>
<Line X1="9" X2="9" Y1="2" Y2="8" Stroke="Silver" StrokeThickness="1" Name="Line2"/>
<Line X1="2" X2="12" Y1="8" Y2="8" Stroke="Silver" StrokeThickness="1" Name="Line3"/>
<Rectangle Fill="Silver" Width="2" Height="7" Canvas.Left="4" Canvas.Top="2" Name="Rectangle"/>
<Line X1="7" X2="7" Y1="9" Y2="12" Stroke="Silver" StrokeThickness="1" Name="Line4"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotateUnpin}"/>
</Trigger>
<Trigger Property="ButtonBase.IsMouseOver" Value="True">
<Setter TargetName="Line1" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line2" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line3" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line4" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Rectangle" Property="Fill" Value="{StaticResource MouseOverPinBrush}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotateUnpin}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style
TargetType="{x:Type TextBox}"
x:Key="TextStyle">
<Setter
Property="OverridesDefaultStyle"
Value="True" />
<Setter
Property="VerticalAlignment"
Value="Center" />
<Setter
Property="FontFamily" Value="Khmer UI" />
<Setter Property="FontSize" Value="12" />
<Setter
Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter
Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TextBoxBase}">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0">
<ScrollViewer
Margin="0"
Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="Margin" Value="4 0" />
<Setter
Property="FontFamily" Value="Khmer UI" />
<Setter Property="FontSize" Value="12" />
</Style>
<Style x:Key="PinThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<StackPanel x:Name="Container"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="ExpandCollapseToggleStyle"
TargetType="{x:Type ToggleButton}">
<Setter
Property="Focusable"
Value="False" />
<Setter
Property="Width"
Value="19" />
<Setter
Property="Height"
Value="13" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type ToggleButton}">
<Border
Width="19"
Height="13"
Background="Transparent">
<Border
Width="9"
Height="9"
BorderThickness="1"
BorderBrush="#FF7898B5"
CornerRadius="1"
SnapsToDevicePixels="true">
<Border.Background>
<LinearGradientBrush
StartPoint="0,0"
EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop
Color="White"
Offset=".2" />
<GradientStop
Color="#FFC0B7A6"
Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path
x:Name="ExpandPath"
Margin="1,1,1,1"
Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z" />
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="IsChecked"
Value="True">
<Setter
Property="Data"
TargetName="ExpandPath"
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="upDownBorderStyle"
TargetType="{x:Type Border}">
<Setter
Property="BorderBrush"
Value="Gray" />
<Setter
Property="HorizontalAlignment"
Value="Stretch" />
<Setter
Property="Margin"
Value="0" />
<Setter
Property="Padding"
Value="0" />
<Setter
Property="Background"
Value="#FFECF7FC" />
<Setter
Property="Height"
Value="14" />
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}"
Value="False">
<Setter
Property="Background"
Value="#FFE0E0E0"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style
x:Key="upButtonStyle"
TargetType="{x:Type RepeatButton}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type RepeatButton}">
<Border
Style="{StaticResource upDownBorderStyle}"
BorderThickness="1 1 1 0">
<ContentPresenter
HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="downButtonStyle"
TargetType="{x:Type RepeatButton}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type RepeatButton}">
<Border
Style="{StaticResource upDownBorderStyle}"
BorderThickness="1 0 1 1">
<ContentPresenter
HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="RefreshButton" TargetType="Button">
<Border
Name="ImageBorder"
CornerRadius="7"
BorderBrush="Transparent"
BorderThickness="1"
Height="14"
Width="14">
<Image Width="9" Height="9" Margin="2 2"
x:Name="RefreshContentImage"
Tag="{Binding}"
Source="{core:GetBitmap Icons.16x16.Refresh}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="ImageBorder" Property="Background" Value="{StaticResource SilverBrushKey}"/>
<Setter TargetName="ImageBorder" Property="BorderBrush" Value="Gray"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="ImageBorder" Property="Background" Value="{StaticResource SilverPressedBrushKey}"/>
<Setter TargetName="ImageBorder" Property="BorderBrush" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>

240
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml

@ -1,240 +0,0 @@ @@ -1,240 +0,0 @@
<UserControl x:Class="Debugger.AddIn.Tooltips.PinDebuggerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:Debugger.AddIn.Tooltips"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.Resources>
<LinearGradientBrush x:Key="DataGridBackground"
StartPoint="0,-0.03"
EndPoint="0,1">
<GradientStop
Color="White" />
<GradientStop
Color="#FFFAFCFE"
Offset="0.983" />
<GradientStop
Color="#FFECF7FC"
Offset="0.07" />
<GradientStop
Color="#FFEEF7FA"
Offset="0.436" />
</LinearGradientBrush>
<Style x:Key="CellStyle"
TargetType="{x:Type DataGridCell}">
<Setter
Property="Focusable"
Value="false" />
<!-- Focusable=true blocks shortcuts if cell is focused -->
<Setter
Property="BorderThickness"
Value="0" />
<Setter Property="Width" Value="Auto" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<!-- disable selection highlight -->
<Setter
Property="Foreground"
Value="Black" />
<Setter
Property="Background"
Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="RowStyle"
TargetType="{x:Type DataGridRow}">
<Setter
Property="Background"
Value="Transparent"></Setter>
</Style>
<Style x:Key="DataGridStyle" TargetType="DataGrid">
<Setter Property="VerticalScrollBarVisibility" Value="Disabled"/>
<Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="GridLinesVisibility" Value="None"/>
<Setter Property="RowHeight" Value="18"/>
<Setter Property="MaxHeight" Value="202"/>
<Setter Property="MinHeight" Value="20" />
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectionUnit" Value="FullRow"/>
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="CanUserAddRows" Value="False"/>
<Setter Property="HeadersVisibility" Value="None"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Background" Value="{StaticResource DataGridBackground}"/>
<Setter Property="CellStyle" Value="{StaticResource CellStyle}"/>
<Setter Property="RowStyle" Value="{StaticResource RowStyle}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Arrow"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<DataGrid
Width="21"
BorderThickness="1,1,0,1"
Background="White"
x:Name="ExpandersGrid"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid
Background="White">
<StackPanel
VerticalAlignment="Center">
<ToggleButton
x:Name="btnExpander"
Style="{StaticResource ExpandCollapseToggleStyle}"
Checked="BtnExpander_Checked"
Unchecked="BtnExpander_Unchecked"
Padding="0"
Margin="0" />
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasChildNodes}"
Value="False">
<Setter
TargetName="btnExpander"
Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid
BorderThickness="0,1,0,1"
Grid.Column="1"
IsEnabled="False"
ColumnWidth="SizeToCells"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}"
Foreground="Black"
Name="dataGrid">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image
Source="{Binding ImageSource}"></Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Name">
<!-- Name -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
BorderBrush="#FFDDDDDD"
BorderThickness="0 0 1 0">
<TextBlock
Style="{StaticResource TextBlockStyle}"
Text="{Binding Path=FullName, Mode=OneWay}"
VerticalAlignment="Center"></TextBlock>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn IsReadOnly="True"
Width="SizeToCells"
Header="Text">
<!-- Text (value) -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox
Style="{StaticResource TextStyle}"
IsEnabled="false"
Text="{Binding Path=Text}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid
MaxWidth="20"
BorderThickness="1"
Grid.Column="2"
x:Name="ImagesGrid"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="Button_Click" Template="{StaticResource RefreshButton}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
<!-- comment textbox -->
<Border
Name="BorderComment"
Background="White"
BorderThickness="1,0,1,1"
BorderBrush="Gray"
Height="0"
MaxHeight="50">
<TextBox
FontFamily="Khmer UI"
BorderBrush="Gray"
BorderThickness="1"
FontSize="12"
Name="CommentTextBox"
TextChanged="CommentTextBox_TextChanged"
Margin="3"/>
</Border>
</StackPanel>
<local:PinCloseControl
VerticalAlignment="Center"
Background="Transparent"
Grid.Column="1"
Margin="5,0,0,0"
x:Name="PinCloseControl">
<local:PinCloseControl.Effect>
<DropShadowEffect
ShadowDepth="5"
Direction="330"
Color="Black"
Opacity="0.5"/>
</local:PinCloseControl.Effect>
</local:PinCloseControl>
</Grid>
</UserControl>

384
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs

@ -1,384 +0,0 @@ @@ -1,384 +0,0 @@
// 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.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Tooltips
{
public partial class PinDebuggerControl : UserControl, IPinDebuggerControl
{
private const double ChildPopupOpenXOffet = 16;
private const double ChildPopupOpenYOffet = 15;
private const int InitialItemsCount = 12;
private const double MINIMUM_OPACITY = .3d;
private WindowsDebugger currentDebugger;
private DebuggerPopup childPopup;
private LazyItemsControl<ITreeNode> lazyExpandersGrid;
private LazyItemsControl<ITreeNode> lazyGrid;
private LazyItemsControl<ITreeNode> lazyImagesGrid;
private IEnumerable<ITreeNode> itemsSource;
public PinDebuggerControl()
{
InitializeComponent();
if (!DebuggerService.IsDebuggerStarted)
Opacity = MINIMUM_OPACITY;
this.PinCloseControl.Opacity = 0;
Loaded += OnLoaded;
this.PinCloseControl.Closed += PinCloseControl_Closed;
this.PinCloseControl.ShowingComment += PinCloseControl_ShowingComment;
this.PinCloseControl.PinningChanged += PinCloseControl_PinningChanged;
BookmarkManager.Removed += OnBookmarkRemoved;
currentDebugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
currentDebugger.DebugStopped += OnDebugStopped;
currentDebugger.ProcessSelected += OnProcessSelected;
if (currentDebugger.DebuggedProcess != null)
currentDebugger.DebuggedProcess.Paused += OnDebuggedProcessPaused;
}
#region Properties
public PinBookmark Mark { get; set; }
public IEnumerable<ITreeNode> ItemsSource
{
get { return this.itemsSource; }
set {
itemsSource = value;
var items = new VirtualizingIEnumerable<ITreeNode>(value);
lazyExpandersGrid = new LazyItemsControl<ITreeNode>(this.ExpandersGrid, InitialItemsCount);
lazyExpandersGrid.ItemsSource = items;
lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount);
lazyGrid.ItemsSource = items;
lazyImagesGrid = new LazyItemsControl<ITreeNode>(this.ImagesGrid, InitialItemsCount);
lazyImagesGrid.ItemsSource = items;
}
}
/// <summary>
/// Relative position of the pin with respect to the screen.
/// </summary>
public Point Location { get; set; }
#endregion
#region Main operations
public void Open()
{
Pin();
}
public void Close()
{
CloseChildPopups();
Unpin();
BookmarkManager.Removed -= OnBookmarkRemoved;
if (currentDebugger != null) {
currentDebugger.DebugStopped -= OnDebugStopped;
currentDebugger.ProcessSelected -= OnProcessSelected;
currentDebugger = null;
}
}
void Pin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if(provider != null) {
var pinLayer = PinningBinding.GetPinlayer(provider.TextEditor);
if (pinLayer != null)
pinLayer.Pin(this);
}
}
void Unpin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if(provider != null) {
var pinLayer = PinningBinding.GetPinlayer(provider.TextEditor);
if (pinLayer != null)
pinLayer.Unpin(this);
}
}
#endregion
#region Debugger events
void OnDebugStopped(object sender, EventArgs e)
{
if (currentDebugger.DebuggedProcess != null)
currentDebugger.DebuggedProcess.Paused -= OnDebuggedProcessPaused;
}
void OnProcessSelected(object sender, ProcessEventArgs e)
{
Opacity = 1d;
if (currentDebugger.DebuggedProcess != null)
currentDebugger.DebuggedProcess.Paused += OnDebuggedProcessPaused;
}
void OnDebuggedProcessPaused(object sender, ProcessEventArgs e)
{
//var nodes = new StackFrameNode(e.Process.SelectedStackFrame).ChildNodes;
// if (!lazyGrid.ItemsSource.ContainsNode(node))
// return;
// TODO : find the current expression so we don't update every pin
// var observable = new List<ITreeNode>();
//
// foreach (var node in lazyGrid.ItemsSource) {
// var resultNode = currentDebugger.GetNode(node.FullName);
// // HACK for updating the pins in tooltip
// observable.Add(resultNode);
// }
//
// // update UI
// var newSource = new VirtualizingIEnumerable<ITreeNode>(observable);
// lazyGrid.ItemsSource = newSource;
// lazyExpandersGrid.ItemsSource = newSource;
}
#endregion
#region Expand button
private ToggleButton expandedButton;
/// <summary>
/// Closes the child popup of this control, if it exists.
/// </summary>
void CloseChildPopups()
{
if (this.expandedButton != null) {
this.expandedButton = null;
// nice simple example of indirect recursion
this.childPopup.CloseSelfAndChildren();
}
}
void BtnExpander_Checked(object sender, RoutedEventArgs e)
{
if (!DebuggerService.IsDebuggerStarted)
return;
var clickedButton = (ToggleButton)e.OriginalSource;
var clickedNode = (ITreeNode)clickedButton.DataContext;
// use device independent units, because child popup Left/Top are in independent units
Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton);
if (clickedButton.IsChecked.GetValueOrDefault(false)) {
this.expandedButton = clickedButton;
// open child Popup
if (this.childPopup == null) {
this.childPopup = new DebuggerPopup(null, ICSharpCode.NRefactory.Location.Empty, false);
this.childPopup.PlacementTarget = this;
this.childPopup.Closed += new EventHandler(PinDebuggerControl_Closed);
this.childPopup.Placement = PlacementMode.Absolute;
}
this.childPopup.IsLeaf = true;
this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet;
this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet;
if (clickedNode.ChildNodes != null) {
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
}
} else {
}
}
void PinDebuggerControl_Closed(object sender, EventArgs e)
{
if (expandedButton != null && expandedButton.IsChecked.GetValueOrDefault(false))
expandedButton.IsChecked = false;
}
void BtnExpander_Unchecked(object sender, RoutedEventArgs e)
{
CloseChildPopups();
}
#endregion
#region PinCloseControl
void PinCloseControl_Closed(object sender, EventArgs e)
{
BookmarkManager.RemoveMark(Mark);
Close();
}
void PinCloseControl_PinningChanged(object sender, EventArgs e)
{
if (this.PinCloseControl.IsChecked) {
BookmarkManager.RemoveMark(Mark);
}
else {
if(BookmarkManager.Bookmarks.Contains(Mark))
BookmarkManager.RemoveMark(Mark);
BookmarkManager.AddMark(Mark);
}
}
void PinCloseControl_ShowingComment(object sender, ShowingCommentEventArgs e)
{
ShowComment(e.ShowComment);
}
void AnimateCloseControl(bool show)
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = show ? 0 : 1;
animation.To = show ? 1 : 0;
animation.BeginTime = new TimeSpan(0, 0, show ? 0 : 1);
animation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
animation.SetValue(Storyboard.TargetProperty, this.PinCloseControl);
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty));
Storyboard board = new Storyboard();
board.Children.Add(animation);
board.Begin(this);
}
#endregion
void OnBookmarkRemoved(object sender, BookmarkEventArgs e)
{
// if the bookmark was removed from pressing the button, return
if (this.PinCloseControl.IsChecked)
return;
if (e.Bookmark is PinBookmark) {
var pin = (PinBookmark)e.Bookmark;
if (pin.Location == Mark.Location && pin.FileName == Mark.FileName) {
Close();
}
}
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
this.CommentTextBox.Text = Mark.Comment;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!DebuggerService.IsDebuggerStarted)
return;
// refresh content
ITreeNode node = ((FrameworkElement)e.OriginalSource).DataContext as ITreeNode;
var resultNode = currentDebugger.GetNode(node.FullName, node.ImageName);
if (resultNode == null)
return;
// HACK for updating the pins in tooltip
var observable = new ObservableCollection<ITreeNode>();
var source = lazyGrid.ItemsSource;
source.ForEach(item => {
if (item.CompareTo(node) == 0)
observable.Add(resultNode);
else
observable.Add(item);
});
Mark.Nodes = observable;
// update UI
var newSource = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = newSource;
lazyExpandersGrid.ItemsSource = newSource;
}
#region Comment
void ShowComment(bool show)
{
if(show && BorderComment.Height != 0)
return;
if(!show && BorderComment.Height != 40)
return;
DoubleAnimation animation = new DoubleAnimation();
animation.From = show ? 0 : 40;
animation.To = show ? 40 : 0;
animation.Duration = new Duration(TimeSpan.FromMilliseconds(300));
animation.SetValue(Storyboard.TargetProperty, BorderComment);
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Border.HeightProperty));
Storyboard board = new Storyboard();
board.Children.Add(animation);
board.Begin(this);
}
void CommentTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
Mark.Comment = this.CommentTextBox.Text;
}
#endregion
#region Overrides
protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
{
AnimateCloseControl(true);
Opacity = 1d;
Cursor = Cursors.Arrow;
base.OnMouseEnter(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
Opacity = 1d;
Cursor = Cursors.Arrow;
base.OnMouseMove(e);
}
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
{
if (DebuggerService.IsDebuggerStarted)
Opacity = 1;
else
Opacity = MINIMUM_OPACITY;
AnimateCloseControl(false);
Cursor = Cursors.IBeam;
base.OnMouseLeave(e);
}
#endregion
}
}

184
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinLayer.cs

@ -1,184 +0,0 @@ @@ -1,184 +0,0 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Refactoring;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Pin layer class. This class handles the pinning and unpinning operations.
/// </summary>
public class PinLayer : Canvas
{
private double verticalOffset = 0;
private double horizontalOffset = 0;
private TextView textView;
/// <summary>
/// PinLayer constructor.
/// </summary>
/// <param name="textArea">Text area for this layer.</param>
public PinLayer(TextArea textArea)
{
textView = textArea.TextView;
textView.VisualLinesChanged += textView_VisualLinesChanged;
}
/// <summary>
/// Pins an element;
/// </summary>
/// <param name="element">Element to pin.</param>
public void Pin(PinDebuggerControl element)
{
if (element == null)
throw new NullReferenceException("Element is null!");
Thumb currentThumb = new Thumb();
// check for saved position
if (!element.Mark.PinPosition.HasValue) {
// this is satisfied when pinning the first time
element.Mark.PinPosition = new Point {
X = element.Location.X + textView.HorizontalOffset,
Y = element.Location.Y + textView.VerticalOffset
};
Canvas.SetTop(currentThumb, element.Location.Y);
Canvas.SetLeft(currentThumb, element.Location.X);
}
else {
// this is satisfied when loading the pins - so we might have hidden pins
element.Location = new Point {
X = element.Mark.PinPosition.Value.X - textView.HorizontalOffset,
Y = element.Mark.PinPosition.Value.Y - textView.VerticalOffset
};
Canvas.SetTop(currentThumb, element.Mark.PinPosition.Value.Y);
Canvas.SetLeft(currentThumb, element.Mark.PinPosition.Value.X);
}
currentThumb.Style = element.TryFindResource("PinThumbStyle") as Style;
currentThumb.ApplyTemplate();
currentThumb.DragDelta += onDragDelta;
currentThumb.DragStarted += currentThumb_DragStarted;
currentThumb.DragCompleted += currentThumb_DragCompleted;
var container = TryFindChild<StackPanel>(currentThumb);
container.Children.Add(element);
this.Children.Add(currentThumb);
}
/// <summary>
/// Unpins an element.
/// </summary>
/// <param name="element">Element to unpin.</param>
public void Unpin(PinDebuggerControl element)
{
if (element == null)
throw new NullReferenceException("Element is null!");
foreach (var thumb in this.Children) {
PinDebuggerControl pinControl = TryFindChild<PinDebuggerControl>((DependencyObject)thumb);
if (pinControl != null && pinControl == element)
{
this.Children.Remove((UIElement)thumb);
element.Close();
break;
}
}
}
void textView_VisualLinesChanged(object sender, EventArgs e)
{
foreach (var ctrl in this.Children) {
var currentThumb = ctrl as Thumb;
PinDebuggerControl pinControl = TryFindChild<PinDebuggerControl>(currentThumb);
if (pinControl != null)
{
// update relative location
Point location = pinControl.Location;
location.X += horizontalOffset - textView.HorizontalOffset;
location.Y += verticalOffset - textView.VerticalOffset;
Canvas.SetLeft(currentThumb, location.X);
Canvas.SetTop(currentThumb, location.Y);
pinControl.Location = location;
pinControl.Mark.PinPosition = new Point {
X = location.X + textView.HorizontalOffset,
Y = location.Y + textView.VerticalOffset,
};
}
}
verticalOffset = textView.VerticalOffset;
horizontalOffset = textView.HorizontalOffset;
}
#region Mouse move
void onDragDelta(object sender, DragDeltaEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
double left = Canvas.GetLeft(currnetThumb) + e.HorizontalChange;
double top = Canvas.GetTop(currnetThumb) + e.VerticalChange;
Canvas.SetLeft(currnetThumb, left);
Canvas.SetTop(currnetThumb, top);
}
void currentThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
var pinControl = TryFindChild<PinDebuggerControl>(currnetThumb);
if (pinControl != null) {
double left = Canvas.GetLeft(currnetThumb);
double top = Canvas.GetTop(currnetThumb);
pinControl.Opacity = 1d;
pinControl.Location = new Point { X = left, Y = top };
// pin's position is with respect to the layer.
pinControl.Mark.PinPosition =
new Point
{
X = textView.HorizontalOffset + left,
Y = textView.VerticalOffset + top
};
}
}
void currentThumb_DragStarted(object sender, DragStartedEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
var pinControl = TryFindChild<PinDebuggerControl>(currnetThumb);
if (pinControl != null)
pinControl.Opacity = 1d;
}
#endregion
#region Static helpers
static T TryFindChild<T>(DependencyObject root) where T : DependencyObject
{
return WpfTreeNavigation.TryFindChild<T>(root);
}
#endregion
}
}

117
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs

@ -1,117 +0,0 @@ @@ -1,117 +0,0 @@
// 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.ObjectModel;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
namespace Debugger.AddIn.Tooltips
{
public class PinningBinding : DefaultLanguageBinding
{
ITextEditor _editor;
PinLayer pinLayer;
public PinningBinding()
{}
public override void Attach(ITextEditor editor)
{
if (editor == null)
return;
var textEditor = editor.GetService(typeof(TextEditor)) as TextEditor;
if (textEditor != null) {
pinLayer = new PinLayer(textEditor.TextArea);
textEditor.TextArea.TextView.InsertLayer(
pinLayer,
KnownLayer.Caret,
LayerInsertionPosition.Above);
}
_editor = editor;
CreatePins(_editor);
base.Attach(editor);
}
public override void Detach()
{
ClosePins(_editor);
pinLayer = null;
base.Detach();
}
public void CreatePins(ITextEditor editor)
{
// load pins
var pins = BookmarkManager.Bookmarks.FindAll(
b => b is PinBookmark && b.FileName == editor.FileName);
foreach (var bookmark in pins) {
var pin = (PinBookmark)bookmark;
pin.Popup = new PinDebuggerControl();
pin.Popup.Mark = pin;
var nodes = new ObservableCollection<ITreeNode>();
foreach (var tuple in pin.SavedNodes) {
string imageName = !string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field";
var node = new Debugger.AddIn.TreeModel.SavedTreeNode(
new ResourceServiceImage(imageName),
tuple.Item2,
tuple.Item3);
node.ImageName = imageName;
nodes.Add(node);
}
pin.SavedNodes.Clear();
pin.Popup.ItemsSource = nodes;
pin.Nodes = nodes;
pinLayer.Pin((PinDebuggerControl)pin.Popup);
}
}
public void ClosePins(ITextEditor editor)
{
// save pins
var pins = BookmarkManager.Bookmarks.FindAll(
b => b is PinBookmark && b.FileName == editor.FileName);
foreach (var bookmark in pins) {
var pin = (PinBookmark)bookmark;
if (!pin.PinPosition.HasValue)
pin.PinPosition = pin.Popup.Location;
// nodes
if (pin.SavedNodes == null)
pin.SavedNodes = new System.Collections.Generic.List<Tuple<string, string, string>>();
foreach (var node in pin.Nodes) {
pin.SavedNodes.Add(
new Tuple<string, string, string>(
"Icons.16x16.Field",
node.FullName,
node.Text));
}
pinLayer.Unpin((PinDebuggerControl)pin.Popup);
pin.Popup = null;
}
}
public static PinLayer GetPinlayer(ITextEditor editor) {
var textEditor = editor.GetService(typeof(TextEditor)) as TextEditor;
if (textEditor != null) {
return textEditor.TextArea.TextView.Layers[3] as PinLayer;
}
return null;
}
}
}

53
src/AddIns/Debugger/Debugger.AddIn/Tooltips/VirtualizingIEnumerable.cs

@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
// 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.Collections.ObjectModel;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// A wrapper around IEnumerable&lt;T&gt; with AddNextItems method for pulling additional items
/// from underlying IEnumerable&lt;T&gt;.
/// Can be used as source for <see cref="LazyItemsControl" />.
/// </summary>
public class VirtualizingIEnumerable<T> : ObservableCollection<T>
{
private IEnumerator<T> originalSourceEnumerator;
public VirtualizingIEnumerable(IEnumerable<T> originalSource)
{
if (originalSource == null)
throw new ArgumentNullException("originalSource");
this.originalSourceEnumerator = originalSource.GetEnumerator();
}
private bool hasNext = true;
/// <summary>
/// False if all items from underlying IEnumerable have already been added.
/// </summary>
public bool HasNext
{
get
{
return this.hasNext;
}
}
/// <summary>
/// Requests next <paramref name="count"/> items from underlying IEnumerable source and adds them to the collection.
/// </summary>
public void AddNextItems(int count)
{
for (int i = 0; i < count; i++) {
if (!originalSourceEnumerator.MoveNext()) {
this.hasNext = false;
break;
}
this.Add(originalSourceEnumerator.Current);
}
}
}
}

125
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs

@ -1,125 +0,0 @@ @@ -1,125 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> LazyGetChildNodesOfArray(TreeNode parent, Expression expression, ArrayDimensions dimensions)
{
if (dimensions.TotalElementCount == 0)
return new TreeNode[] { new TreeNode(null, "(empty)", null, null, parent, _ => null) };
return new ArrayRangeNode(parent, expression, dimensions, dimensions).ChildNodes;
}
}
/// <summary> This is a partent node for all elements within a given bounds </summary>
public class ArrayRangeNode: TreeNode
{
const int MaxElementCount = 100;
Expression arrayTarget;
ArrayDimensions bounds;
ArrayDimensions originalBounds;
public ArrayRangeNode(TreeNode parent, Expression arrayTarget, ArrayDimensions bounds, ArrayDimensions originalBounds)
: base(parent)
{
this.arrayTarget = arrayTarget;
this.bounds = bounds;
this.originalBounds = originalBounds;
this.Name = GetName();
this.childNodes = LazyGetChildren();
}
public override IEnumerable<TreeNode> ChildNodes {
get { return base.ChildNodes; }
}
string GetName()
{
StringBuilder name = new StringBuilder();
bool isFirst = true;
name.Append("[");
for(int i = 0; i < bounds.Count; i++) {
if (!isFirst) name.Append(", ");
isFirst = false;
ArrayDimension dim = bounds[i];
ArrayDimension originalDim = originalBounds[i];
if (dim.Count == 0) {
throw new DebuggerException("Empty dimension");
} else if (dim.Count == 1) {
name.Append(dim.LowerBound.ToString());
} else if (dim.Equals(originalDim)) {
name.Append("*");
} else {
name.Append(dim.LowerBound);
name.Append("..");
name.Append(dim.UpperBound);
}
}
name.Append("]");
return name.ToString();
}
static string GetName(int[] indices)
{
StringBuilder sb = new StringBuilder(indices.Length * 4);
sb.Append("[");
bool isFirst = true;
foreach(int index in indices) {
if (!isFirst) sb.Append(", ");
sb.Append(index.ToString());
isFirst = false;
}
sb.Append("]");
return sb.ToString();
}
IEnumerable<TreeNode> LazyGetChildren()
{
// The whole array is small - just add all elements as childs
if (bounds.TotalElementCount <= MaxElementCount) {
foreach(int[] indices in bounds.Indices) {
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var expression = new ExpressionNode(this, image, GetName(indices), arrayTarget.AppendIndexer(indices));
expression.ImageName = imageName;
yield return expression;
}
yield break;
}
// Find a dimension of size at least 2
int splitDimensionIndex = bounds.Count - 1;
for(int i = 0; i < bounds.Count; i++) {
if (bounds[i].Count > 1) {
splitDimensionIndex = i;
break;
}
}
ArrayDimension splitDim = bounds[splitDimensionIndex];
// Split the dimension
int elementsPerSegment = 1;
while (splitDim.Count > elementsPerSegment * MaxElementCount) {
elementsPerSegment *= MaxElementCount;
}
for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) {
List<ArrayDimension> newDims = new List<ArrayDimension>(bounds);
newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound));
yield return new ArrayRangeNode(this, arrayTarget, new ArrayDimensions(newDims), originalBounds);
}
yield break;
}
}
}

144
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs

@ -1,144 +0,0 @@ @@ -1,144 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> LazyGetChildNodesOfObject(TreeNode current, Expression targetObject, DebugType shownType)
{
MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
DebugType baseType = (DebugType)shownType.BaseType;
if (baseType != null) {
yield return new TreeNode(
DebuggerResourceService.GetImage("Icons.16x16.Class"),
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.BaseClass}"),
baseType.Name,
baseType.FullName,
current,
newNode => baseType.FullName == "System.Object" ? null : Utils.LazyGetChildNodesOfObject(newNode, targetObject, baseType)
);
}
if (nonPublicInstance.Length > 0) {
yield return new TreeNode(
null,
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicMembers}"),
string.Empty,
string.Empty,
current,
newNode => Utils.LazyGetMembersOfObject(newNode, targetObject, nonPublicInstance)
);
}
if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) {
yield return new TreeNode(
null,
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.StaticMembers}"),
string.Empty,
string.Empty,
current,
p => {
var children = Utils.LazyGetMembersOfObject(p, targetObject, publicStatic);
if (nonPublicStatic.Length > 0) {
TreeNode nonPublicStaticNode = new TreeNode(
null,
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicStaticMembers}"),
string.Empty,
string.Empty,
p,
newNode => Utils.LazyGetMembersOfObject(newNode, targetObject, nonPublicStatic)
);
children = Utils.PrependNode(nonPublicStaticNode, children);
}
return children;
}
);
}
DebugType iListType = (DebugType)shownType.GetInterface(typeof(IList).FullName);
if (iListType != null) {
yield return new IListNode(current, targetObject);
} else {
DebugType iEnumerableType, itemType;
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
yield return new IEnumerableNode(current, targetObject, itemType);
}
}
foreach(TreeNode node in LazyGetMembersOfObject(current, targetObject, publicInstance)) {
yield return node;
}
}
public static IEnumerable<TreeNode> LazyGetMembersOfObject(TreeNode parent, Expression expression, MemberInfo[] members)
{
List<TreeNode> nodes = new List<TreeNode>();
foreach(MemberInfo memberInfo in members) {
string imageName;
var image = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo, out imageName);
var exp = new ExpressionNode(parent, image, memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo));
exp.ImageName = imageName;
nodes.Add(exp);
}
nodes.Sort();
return nodes;
}
public static IEnumerable<TreeNode> LazyGetItemsOfIList(TreeNode parent, Expression targetObject)
{
// Add a cast, so that we are sure the expression has an indexer.
// (The expression can be e.g. of type 'object' but its value is a List.
// Without the cast, evaluating "expr[i]" would fail, because object does not have an indexer).
targetObject = targetObject.CastToIList();
int count = 0;
GetValueException error = null;
try {
count = targetObject.GetIListCount();
} catch (GetValueException e) {
// Cannot yield a value in the body of a catch clause (CS1631)
error = e;
}
if (error != null) {
yield return new TreeNode(null, "(error)", error.Message, null, null, _ => null);
} else if (count == 0) {
yield return new TreeNode(null, "(empty)", null, null, null, _ => null);
} else {
for(int i = 0; i < count; i++) {
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var itemNode = new ExpressionNode(parent, image, "[" + i + "]", targetObject.AppendIndexer(i));
itemNode.ImageName = imageName;
yield return itemNode;
}
}
}
public static IEnumerable<TreeNode> PrependNode(TreeNode node, IEnumerable<TreeNode> rest)
{
yield return node;
if (rest != null) {
foreach(TreeNode absNode in rest) {
yield return absNode;
}
}
}
}
}

25
src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs

@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using ICSharpCode.SharpDevelop;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// Gets resources the way suitable for Debugger.AddIn.
/// </summary>
public static class DebuggerResourceService
{
/// <summary>
/// Gets image with given name from resources.
/// </summary>
/// <param name="resourceName">Resource name of the image.</param>
public static IImage GetImage(string resourceName)
{
return new ResourceServiceImage(resourceName);
}
}
}

462
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs

@ -1,462 +0,0 @@ @@ -1,462 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Debugger.AddIn.Visualizers;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// Node in the tree which can be defined by a debugger expression.
/// The expression will be lazily evaluated when needed.
/// </summary>
public class ExpressionNode: TreeNode, ISetText, INotifyPropertyChanged
{
bool evaluated;
Expression expression;
bool canSetText;
GetValueException error;
string fullText;
public bool Evaluated {
get { return evaluated; }
set { evaluated = value; }
}
public Expression Expression {
get { return expression; }
}
public override bool CanSetText {
get {
if (!evaluated) EvaluateExpression();
return canSetText;
}
}
public GetValueException Error {
get {
if (!evaluated) EvaluateExpression();
return error;
}
}
public string FullText {
get { return fullText; }
}
public override string Text {
get {
if (!evaluated) EvaluateExpression();
return base.Text;
}
set {
if (value != base.Text) {
base.Text = value;
NotifyPropertyChanged("Text");
}
}
}
public override string FullName {
get {
return this.expression.PrettyPrint() ?? Name.Trim();
}
}
public override string Type {
get {
if (!evaluated) EvaluateExpression();
return base.Type;
}
}
public override IEnumerable<TreeNode> ChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.ChildNodes;
}
}
public override bool HasChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.HasChildNodes;
}
}
/// <summary> Used to determine available VisualizerCommands </summary>
private DebugType expressionType;
/// <summary> Used to determine available VisualizerCommands </summary>
private bool valueIsNull = true;
private IEnumerable<IVisualizerCommand> visualizerCommands;
public override IEnumerable<IVisualizerCommand> VisualizerCommands {
get {
if (visualizerCommands == null) {
visualizerCommands = getAvailableVisualizerCommands();
}
return visualizerCommands;
}
}
private IEnumerable<IVisualizerCommand> getAvailableVisualizerCommands()
{
if (!evaluated) EvaluateExpression();
if (this.expressionType == null) {
// no visualizers if EvaluateExpression failed
yield break;
}
if (this.valueIsNull) {
// no visualizers if evaluated value is null
yield break;
}
/*if (this.expressionType.IsPrimitive || this.expressionType.IsSystemDotObject() || this.expressionType.IsEnum()) {
// no visualizers for primitive types
yield break;
}*/
foreach (var descriptor in VisualizerDescriptors.GetAllDescriptors()) {
if (descriptor.IsVisualizerAvailable(this.expressionType)) {
yield return descriptor.CreateVisualizerCommand(this.Expression);
}
}
}
public ExpressionNode(TreeNode parent, IImage image, string name, Expression expression)
: base(parent)
{
this.IconImage = image;
this.Name = name;
this.expression = expression;
}
void EvaluateExpression()
{
evaluated = true;
Value val;
try {
var process = WindowsDebugger.DebuggedProcess;
if (process == null) return;
StackFrame frame = process.GetCurrentExecutingFrame();
if (frame == null) return;
var debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
object data = debugger.debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken,
frame.MethodInfo.MetadataToken,
Name);
if (expression is MemberReferenceExpression) {
var memberExpression = (MemberReferenceExpression)expression;
memberExpression.TargetObject.UserData = data;
} else {
expression.UserData = data;
}
// evaluate expression
val = expression.Evaluate(process);
} catch (GetValueException e) {
error = e;
this.Text = e.Message;
return;
}
this.canSetText = val.Type.IsPrimitive;
this.expressionType = val.Type;
this.Type = val.Type.Name;
this.valueIsNull = val.IsNull;
// Note that these return enumerators so they are lazy-evaluated
if (val.IsNull) {
} else if (val.Type.IsPrimitive || val.Type.FullName == typeof(string).FullName) { // Must be before IsClass
} else if (val.Type.IsArray) { // Must be before IsClass
if (val.ArrayLength > 0)
this.childNodes = Utils.LazyGetChildNodesOfArray(this, this.Expression, val.ArrayDimensions);
} else if (val.Type.IsClass || val.Type.IsValueType) {
if (val.Type.FullNameWithoutGenericArguments == typeof(List<>).FullName) {
if ((int)val.GetMemberValue("_size").PrimitiveValue > 0)
this.childNodes = Utils.LazyGetItemsOfIList(this, this.expression);
} else {
this.childNodes = Utils.LazyGetChildNodesOfObject(this, this.Expression, val.Type);
}
} else if (val.Type.IsPointer) {
Value deRef = val.Dereference();
if (deRef != null) {
this.childNodes = new ExpressionNode [] { new ExpressionNode(this, this.IconImage, "*" + this.Name, this.Expression.AppendDereference()) };
}
}
if (DebuggingOptions.Instance.ICorDebugVisualizerEnabled) {
TreeNode info = ICorDebug.GetDebugInfoRoot(val.AppDomain, val.CorValue);
this.childNodes = Utils.PrependNode(info, this.ChildNodes);
}
// Do last since it may expire the object
if (val.Type.IsInteger) {
fullText = FormatInteger(val.PrimitiveValue);
} else if (val.Type.IsPointer) {
fullText = String.Format("0x{0:X}", val.PointerAddress);
} else if ((val.Type.FullName == typeof(string).FullName ||
val.Type.FullName == typeof(char).FullName) && !val.IsNull) {
try {
fullText = '"' + Escape(val.InvokeToString()) + '"';
} catch (GetValueException e) {
error = e;
fullText = e.Message;
return;
}
} else if ((val.Type.IsClass || val.Type.IsValueType) && !val.IsNull) {
try {
fullText = val.InvokeToString();
} catch (GetValueException e) {
error = e;
fullText = e.Message;
return;
}
} else {
fullText = val.AsString();
}
this.Text = (fullText.Length > 256) ? fullText.Substring(0, 256) + "..." : fullText;
}
string Escape(string source)
{
return source.Replace("\n", "\\n")
.Replace("\t", "\\t")
.Replace("\r", "\\r")
.Replace("\0", "\\0")
.Replace("\b", "\\b")
.Replace("\a", "\\a")
.Replace("\f", "\\f")
.Replace("\v", "\\v")
.Replace("\"", "\\\"");
}
string FormatInteger(object i)
{
if (DebuggingOptions.Instance.ShowIntegersAs == ShowIntegersAs.Decimal)
return i.ToString();
string hex = null;
for(int len = 1;; len *= 2) {
hex = string.Format("{0:X" + len + "}", i);
if (hex.Length == len)
break;
}
if (DebuggingOptions.Instance.ShowIntegersAs == ShowIntegersAs.Hexadecimal) {
return "0x" + hex;
} else {
if (ShowAsHex(i)) {
return String.Format("{0} (0x{1})", i, hex);
} else {
return i.ToString();
}
}
}
bool ShowAsHex(object i)
{
ulong val;
if (i is sbyte || i is short || i is int || i is long) {
unchecked { val = (ulong)Convert.ToInt64(i); }
if (val > (ulong)long.MaxValue)
val = ~val + 1;
} else {
val = Convert.ToUInt64(i);
}
if (val >= 0x10000)
return true;
int ones = 0; // How many 1s there is
int runs = 0; // How many runs of 1s there is
int size = 0; // Size of the integer in bits
while(val != 0) { // There is at least one 1
while((val & 1) == 0) { // Skip 0s
val = val >> 1;
size++;
}
while((val & 1) == 1) { // Skip 1s
val = val >> 1;
size++;
ones++;
}
runs++;
}
return size >= 7 && runs <= (size + 7) / 8;
}
public override bool SetText(string newText)
{
string fullName = FullName;
Value val = null;
try {
val = this.Expression.Evaluate(WindowsDebugger.DebuggedProcess);
if (val.Type.IsInteger && newText.StartsWith("0x")) {
try {
val.PrimitiveValue = long.Parse(newText.Substring(2), NumberStyles.HexNumber);
} catch (FormatException) {
throw new NotSupportedException();
} catch (OverflowException) {
throw new NotSupportedException();
}
} else {
val.PrimitiveValue = newText;
}
this.Text = newText;
return true;
} catch (NotSupportedException) {
string format = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.CannotSetValue.BadFormat");
string msg = string.Format(format, newText, val.Type.PrimitiveType);
MessageService.ShowMessage(msg ,"${res:MainWindow.Windows.Debug.LocalVariables.CannotSetValue.Title}");
} catch (COMException) {
// COMException (0x80131330): Cannot perfrom SetValue on non-leaf frames.
// Happens if trying to set value after exception is breaked
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.LocalVariables.CannotSetValue.UnknownError}",
"${res:MainWindow.Windows.Debug.LocalVariables.CannotSetValue.Title}");
}
return false;
}
public static IImage GetImageForThis(out string imageName)
{
imageName = "Icons.16x16.Parameter";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForParameter(out string imageName)
{
imageName = "Icons.16x16.Parameter";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForLocalVariable(out string imageName)
{
imageName = "Icons.16x16.Local";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForArrayIndexer(out string imageName)
{
imageName = "Icons.16x16.Field";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForMember(IDebugMemberInfo memberInfo, out string imageName)
{
string name = string.Empty;
if (memberInfo.IsPublic) {
} else if (memberInfo.IsAssembly) {
name += "Internal";
} else if (memberInfo.IsFamily) {
name += "Protected";
} else if (memberInfo.IsPrivate) {
name += "Private";
}
if (memberInfo is FieldInfo) {
name += "Field";
} else if (memberInfo is PropertyInfo) {
name += "Property";
} else if (memberInfo is MethodInfo) {
name += "Method";
} else {
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
imageName = "Icons.16x16." + name;
return DebuggerResourceService.GetImage(imageName);
}
// public ContextMenuStrip GetContextMenu()
// {
// if (this.Error != null) return GetErrorContextMenu();
//
// ContextMenuStrip menu = new ContextMenuStrip();
//
// ToolStripMenuItem copyItem;
// copyItem = new ToolStripMenuItem();
// copyItem.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.CopyToClipboard");
// copyItem.Checked = false;
// copyItem.Click += delegate {
// ClipboardWrapper.SetText(fullText);
// };
// ToolStripMenuItem hexView;
// hexView = new ToolStripMenuItem();
// hexView.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.ShowInHexadecimal");
// hexView.Checked = DebuggingOptions.Instance.ShowValuesInHexadecimal;
// hexView.Click += delegate {
// // refresh all pads that use ValueNode for display
// DebuggingOptions.Instance.ShowValuesInHexadecimal = !DebuggingOptions.Instance.ShowValuesInHexadecimal;
// // always check if instance is null, might be null if pad is not opened
// if (LocalVarPad.Instance != null)
// LocalVarPad.Instance.RefreshPad();
// if (WatchPad.Instance != null)
// WatchPad.Instance.RefreshPad();
// };
// menu.Items.AddRange(new ToolStripItem[] {
// copyItem,
// //hexView
// });
//
// return menu;
// }
public ContextMenuStrip GetErrorContextMenu()
{
ContextMenuStrip menu = new ContextMenuStrip();
ToolStripMenuItem showError;
showError = new ToolStripMenuItem();
showError.Text = StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.ShowFullError}");
showError.Checked = false;
showError.Click += delegate {
MessageService.ShowException(error, null);
};
menu.Items.AddRange(new ToolStripItem[] {
showError
});
return menu;
}
public static WindowsDebugger WindowsDebugger {
get {
return (WindowsDebugger)DebuggerService.CurrentDebugger;
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(info));
}
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Windows.Forms;
namespace Debugger.AddIn.TreeModel
{
public interface IContextMenu
{
ContextMenuStrip GetContextMenu();
}
}

158
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs

@ -1,158 +0,0 @@ @@ -1,158 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using Debugger.Interop.CorDebug;
using System;
using System.Collections.Generic;
using Debugger.MetaData;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
public class ICorDebug
{
public class InfoNode: TreeNode
{
List<TreeNode> children;
public InfoNode(TreeNode parent, string name, string text)
: this(parent, name, text, _ => null)
{
}
public InfoNode(TreeNode parent, string name, string text, Func<TreeNode, List<TreeNode>> children)
: base(parent)
{
this.Name = name;
this.Text = text;
this.children = children(this);
}
public override IEnumerable<TreeNode> ChildNodes {
get { return children; }
}
public void AddChild(string name, string text)
{
if (children == null) {
children = new List<TreeNode>();
}
children.Add(new InfoNode(this, name, text));
}
public void AddChild(string name, string text, Func<TreeNode, List<TreeNode>> subChildren)
{
if (children == null) {
children = new List<TreeNode>();
}
children.Add(new InfoNode(this, name, text, p => subChildren(p)));
}
}
public static InfoNode GetDebugInfoRoot(AppDomain appDomain, ICorDebugValue corValue)
{
return new InfoNode(null, "ICorDebug", "", p => GetDebugInfo(p, appDomain, corValue));
}
public static List<TreeNode> GetDebugInfo(TreeNode parent, AppDomain appDomain, ICorDebugValue corValue)
{
List<TreeNode> items = new List<TreeNode>();
if (corValue is ICorDebugValue) {
InfoNode info = new InfoNode(parent, "ICorDebugValue", "");
info.AddChild("Address", corValue.GetAddress().ToString("X8"));
info.AddChild("Type", ((CorElementType)corValue.GetTheType()).ToString());
info.AddChild("Size", corValue.GetSize().ToString());
items.Add(info);
}
if (corValue is ICorDebugValue2) {
InfoNode info = new InfoNode(parent, "ICorDebugValue2", "");
ICorDebugValue2 corValue2 = (ICorDebugValue2)corValue;
string fullname;
try {
fullname = DebugType.CreateFromCorType(appDomain, corValue2.GetExactType()).FullName;
} catch (DebuggerException e) {
fullname = e.Message;
}
info.AddChild("ExactType", fullname);
items.Add(info);
}
if (corValue is ICorDebugGenericValue) {
InfoNode info = new InfoNode(parent, "ICorDebugGenericValue", "");
try {
byte[] bytes = ((ICorDebugGenericValue)corValue).GetRawValue();
for(int i = 0; i < bytes.Length; i += 8) {
string val = "";
for(int j = i; j < bytes.Length && j < i + 8; j++) {
val += bytes[j].ToString("X2") + " ";
}
info.AddChild("Value" + i.ToString("X2"), val);
}
} catch (ArgumentException) {
info.AddChild("Value", "N/A");
}
items.Add(info);
}
if (corValue is ICorDebugReferenceValue) {
InfoNode info = new InfoNode(parent, "ICorDebugReferenceValue", "");
ICorDebugReferenceValue refValue = (ICorDebugReferenceValue)corValue;
info.AddChild("IsNull", (refValue.IsNull() != 0).ToString());
if (refValue.IsNull() == 0) {
info.AddChild("Value", refValue.GetValue().ToString("X8"));
if (refValue.Dereference() != null) {
info.AddChild("Dereference", "", p => GetDebugInfo(p, appDomain, refValue.Dereference()));
} else {
info.AddChild("Dereference", "N/A");
}
}
items.Add(info);
}
if (corValue is ICorDebugHeapValue) {
InfoNode info = new InfoNode(parent, "ICorDebugHeapValue", "");
items.Add(info);
}
if (corValue is ICorDebugHeapValue2) {
InfoNode info = new InfoNode(parent, "ICorDebugHeapValue2", "");
items.Add(info);
}
if (corValue is ICorDebugObjectValue) {
InfoNode info = new InfoNode(parent, "ICorDebugObjectValue", "");
ICorDebugObjectValue objValue = (ICorDebugObjectValue)corValue;
info.AddChild("Class", objValue.GetClass().GetToken().ToString("X8"));
info.AddChild("IsValueClass", (objValue.IsValueClass() != 0).ToString());
items.Add(info);
}
if (corValue is ICorDebugObjectValue2) {
InfoNode info = new InfoNode(parent, "ICorDebugObjectValue2", "");
items.Add(info);
}
if (corValue is ICorDebugBoxValue) {
InfoNode info = new InfoNode(parent, "ICorDebugBoxValue", "");
ICorDebugBoxValue boxValue = (ICorDebugBoxValue)corValue;
info.AddChild("Object", "", p => GetDebugInfo(p, appDomain, boxValue.GetObject()));
items.Add(info);
}
if (corValue is ICorDebugStringValue) {
InfoNode info = new InfoNode(parent, "ICorDebugStringValue", "");
ICorDebugStringValue stringValue = (ICorDebugStringValue)corValue;
info.AddChild("Length", stringValue.GetLength().ToString());
info.AddChild("String", stringValue.GetString());
items.Add(info);
}
if (corValue is ICorDebugArrayValue) {
InfoNode info = new InfoNode(parent, "ICorDebugArrayValue", "");
info.AddChild("...", "...");
items.Add(info);
}
if (corValue is ICorDebugHandleValue) {
InfoNode info = new InfoNode(parent, "ICorDebugHandleValue", "");
ICorDebugHandleValue handleValue = (ICorDebugHandleValue)corValue;
info.AddChild("HandleType", handleValue.GetHandleType().ToString());
items.Add(info);
}
return items;
}
}
}

32
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// IEnumerable node in the variable tree.
/// </summary>
public class IEnumerableNode : TreeNode
{
Expression targetObject;
Expression debugListExpression;
public IEnumerableNode(TreeNode parent, Expression targetObject, DebugType itemType)
: base(parent)
{
this.targetObject = targetObject;
this.Name = "IEnumerable";
this.Text = "Expanding will enumerate the IEnumerable";
DebugType debugListType;
this.debugListExpression = DebuggerHelpers.CreateDebugListExpression(targetObject, itemType, out debugListType);
this.childNodes = Utils.LazyGetItemsOfIList(this, this.debugListExpression);
}
}
}

33
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using Debugger.AddIn.Visualizers.Utils;
using ICSharpCode.NRefactory.Ast;
using System.Collections;
using System.Collections.Generic;
using Debugger.MetaData;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.TreeModel
{
public class IListNode : TreeNode
{
Expression targetList;
int listCount;
public IListNode(TreeNode parent, Expression targetListObject)
: base(parent)
{
this.targetList = targetListObject;
this.Name = "IList";
this.listCount = this.targetList.GetIListCount();
this.childNodes = Utils.LazyGetItemsOfIList(this, this.targetList);
}
public override bool HasChildNodes {
get { return this.listCount > 0; }
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
namespace Debugger.AddIn.TreeModel
{
public interface ISetText
{
bool CanSetText { get; }
bool SetText(string text);
}
}

31
src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
// 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 ICSharpCode.SharpDevelop;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// Description of SavedTreeNode.
/// </summary>
public class SavedTreeNode : TreeNode
{
public override bool CanSetText {
get { return true; }
}
public SavedTreeNode(IImage image, string fullname, string text)
: base(null)
{
base.IconImage = image;
FullName = fullname;
Text = text;
}
public override bool SetText(string newValue) {
Text = newValue;
return false;
}
}
}

39
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs → src/AddIns/Debugger/Debugger.AddIn/TreeModel/SharpTreeNodeAdapter.cs

@ -15,33 +15,29 @@ using ICSharpCode.TreeView; @@ -15,33 +15,29 @@ using ICSharpCode.TreeView;
namespace Debugger.AddIn.Pads.Controls
{
public class TreeNodeWrapper : SharpTreeNode
public class SharpTreeNodeAdapter : SharpTreeNode
{
public TreeNodeWrapper(TreeNode node)
public SharpTreeNodeAdapter(TreeNode node)
{
if (node == null)
throw new ArgumentNullException("node");
Node = node;
LazyLoading = true;
this.Node = node;
this.LazyLoading = true;
}
public TreeNode Node { get; private set; }
public override object Text {
get { return Node.Name; }
}
public override object Icon {
get { return Node.ImageSource; }
get { return this.Node.Image != null ? this.Node.Image.ImageSource : null; }
}
public override bool ShowExpander {
get { return Node.HasChildNodes; }
get { return this.Node.GetChildren != null; }
}
public override bool CanDelete()
{
return Parent is WatchRootNode;
return this.Node.CanDelete;
}
public override void Delete()
@ -51,15 +47,13 @@ namespace Debugger.AddIn.Pads.Controls @@ -51,15 +47,13 @@ namespace Debugger.AddIn.Pads.Controls
protected override void LoadChildren()
{
if (Node.HasChildNodes) {
((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess
.EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(Node.ChildNodes.Select(node => node.ToSharpTreeNode())));
if (this.Node.GetChildren != null) {
var process = WindowsDebugger.CurrentProcess;
process.EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(this.Node.GetChildren().Select(node => node.ToSharpTreeNode())));
}
}
}
public class WatchRootNode : SharpTreeNode
{
/*
public override bool CanDrop(System.Windows.DragEventArgs e, int index)
{
e.Effects = DragDropEffects.None;
@ -79,15 +73,14 @@ namespace Debugger.AddIn.Pads.Controls @@ -79,15 +73,14 @@ namespace Debugger.AddIn.Pads.Controls
string language = ProjectService.CurrentProject.Language;
// FIXME languages
TextNode text = new TextNode(null, e.Data.GetData(DataFormats.StringFormat).ToString(),
language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp);
var text = new TreeNode(e.Data.GetData(DataFormats.StringFormat).ToString(), null);
var node = text.ToSharpTreeNode();
if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.FullName == ((TreeNodeWrapper)n).Node.FullName))
if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.Name == ((SharpTreeNodeAdapter)n).Node.Name))
WatchPad.Instance.WatchList.WatchItems.Add(node);
WatchPad.Instance.InvalidatePad();
WindowsDebugger.RefreshPads();
}
*/
}
}

67
src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs

@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Collections.Generic;
using Debugger.MetaData;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.TreeModel
{
public class StackFrameNode: TreeNode
{
StackFrame stackFrame;
public StackFrame StackFrame {
get { return stackFrame; }
}
public StackFrameNode(StackFrame stackFrame)
: base(null)
{
this.stackFrame = stackFrame;
this.Name = stackFrame.MethodInfo.Name;
this.childNodes = LazyGetChildNodes();
}
IEnumerable<TreeNode> LazyGetChildNodes()
{
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
string imageName;
var image = ExpressionNode.GetImageForParameter(out imageName);
var expression = new ExpressionNode(this, image, par.Name, par.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
if (this.stackFrame.HasSymbols) {
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(this, image, locVar.Name, locVar.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
} else {
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
if (debugger.debuggerDecompilerService != null) {
int typeToken = this.stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = this.stackFrame.MethodInfo.MetadataToken;
foreach (var localVar in debugger.debuggerDecompilerService.GetLocalVariables(typeToken, methodToken)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(this, image, localVar, ExpressionEvaluator.ParseExpression(localVar, SupportedLanguage.CSharp));
expression.ImageName = imageName;
yield return expression;
}
}
}
if (stackFrame.Thread.CurrentException != null) {
yield return new ExpressionNode(this, null, "__exception", new IdentifierExpression("__exception"));
}
}
}
}

185
src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs

@ -15,140 +15,117 @@ namespace Debugger.AddIn.TreeModel @@ -15,140 +15,117 @@ namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// A node in the variable tree.
/// The node is immutable.
/// </summary>
public class TreeNode : ITreeNode
public class TreeNode : INotifyPropertyChanged
{
IImage iconImage = null;
string name = string.Empty;
string imageName = string.Empty;
string text = string.Empty;
string type = string.Empty;
protected IEnumerable<TreeNode> childNodes = null;
/// <summary>
/// The image displayed for this node.
/// </summary>
public IImage IconImage {
get { return iconImage; }
protected set { iconImage = value; }
}
/// <summary>
/// System.Windows.Media.ImageSource version of <see cref="IconImage"/>.
/// </summary>
public ImageSource ImageSource {
get {
return iconImage == null ? null : iconImage.ImageSource;
}
}
/// <summary>
/// System.Drawing.Image version of <see cref="IconImage"/>.
/// </summary>
public Image Image {
get {
return iconImage == null ? null : iconImage.Bitmap;
}
}
public string Name {
get { return name; }
set { name = value; }
}
public string ImageName {
get { return imageName; }
set { imageName = value; }
}
public virtual string FullName {
get { return name; }
set { name = value; }
}
public virtual string Text
{
get { return text; }
set { text = value; }
}
public virtual string Type {
get { return type; }
protected set { type = value; }
}
public event EventHandler<PropertyEventArgs> PropertyRead;
public event PropertyChangedEventHandler PropertyChanged;
public virtual TreeNode Parent { get; protected set; }
IImage image;
string name;
string value;
string type;
public virtual IEnumerable<TreeNode> ChildNodes {
get { return childNodes; }
}
public bool CanDelete { get; set; }
IEnumerable<ITreeNode> ITreeNode.ChildNodes {
get { return childNodes; }
public IImage Image {
get {
OnPropertyRead("Image");
return this.image;
}
set {
if (this.image != value) {
this.image = value;
OnPropertyChanged("Image");
}
}
}
public virtual bool HasChildNodes {
get { return childNodes != null; }
public string Name {
get {
OnPropertyRead("Name");
return this.name;
}
set {
if (this.name != value) {
this.name = value;
OnPropertyChanged("Name");
}
}
}
public virtual bool CanSetText {
get { return false; }
}
public bool CanSetName { get; set; }
public virtual IEnumerable<IVisualizerCommand> VisualizerCommands {
public string Value {
get {
return null;
OnPropertyRead("Value");
return this.value;
}
set {
if (this.value != value) {
this.value = value;
OnPropertyChanged("Value");
}
}
}
public virtual bool HasVisualizerCommands {
public bool CanSetValue { get; set; }
public string Type {
get {
return (VisualizerCommands != null) && (VisualizerCommands.Count() > 0);
OnPropertyRead("Type");
return this.type;
}
set {
if (this.type != value) {
this.type = value;
OnPropertyChanged("Type");
}
}
}
public bool IsPinned { get; set; }
public Func<IEnumerable<TreeNode>> GetChildren { get; protected set; }
public TreeNode(TreeNode parent)
{
this.Parent = parent;
public bool HasChildren {
get { return GetChildren != null; }
}
public TreeNode(IImage iconImage, string name, string text, string type, TreeNode parent, Func<TreeNode, IEnumerable<TreeNode>> childNodes)
: this(parent)
{
if (childNodes == null)
throw new ArgumentNullException("childNodes");
this.iconImage = iconImage;
this.name = name;
this.text = text;
this.type = type;
this.childNodes = childNodes(this);
}
public IEnumerable<IVisualizerCommand> VisualizerCommands { get; protected set; }
public bool HasVisualizerCommands { get; protected set; }
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
public TreeNode(string name, Func<IEnumerable<TreeNode>> getChildren)
{
TreeNode other = obj as TreeNode;
if (other == null)
return false;
return this.FullName == other.FullName;
this.Name = name;
this.GetChildren = getChildren;
}
public override int GetHashCode()
public TreeNode(string imageName, string name, string value, string type, Func<IEnumerable<TreeNode>> getChildren)
{
return this.FullName.GetHashCode();
this.Image = string.IsNullOrEmpty(imageName) ? null : new ResourceServiceImage(imageName);
this.Name = name;
this.Value = value;
this.Type = type;
this.GetChildren = getChildren;
}
#endregion
public int CompareTo(ITreeNode other)
protected virtual void OnPropertyRead(string name)
{
return this.FullName.CompareTo(other.FullName);
if (PropertyRead != null) {
PropertyRead(this, new PropertyEventArgs() { Name = name});
}
}
public virtual bool SetText(string newValue) {
return false;
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
public class PropertyEventArgs: EventArgs
{
public string Name { get; set; }
}
}

10
src/AddIns/Debugger/Debugger.AddIn/TreeModel/Utils.cs

@ -19,7 +19,7 @@ namespace Debugger.AddIn.TreeModel @@ -19,7 +19,7 @@ namespace Debugger.AddIn.TreeModel
{
public static void EnqueueWork(this Process process, Dispatcher dispatcher, Action work)
{
var debuggeeStateWhenEnqueued = process.DebuggeeState;
long debuggeeStateWhenEnqueued = process.DebuggeeState;
// Always ask the scheduler to do only one piece of work at a time
// - this might actually be completely ok as we are not waiting anywhere between thread
dispatcher.BeginInvoke(
@ -44,7 +44,7 @@ namespace Debugger.AddIn.TreeModel @@ -44,7 +44,7 @@ namespace Debugger.AddIn.TreeModel
public static void EnqueueForEach<T>(this Process process, Dispatcher dispatcher, IList<T> items, Action<T> work)
{
DebuggeeState debuggeeStateWhenEnqueued = process.DebuggeeState;
long debuggeeStateWhenEnqueued = process.DebuggeeState;
dispatcher.BeginInvoke(
DispatcherPriority.Normal,
@ -52,7 +52,7 @@ namespace Debugger.AddIn.TreeModel @@ -52,7 +52,7 @@ namespace Debugger.AddIn.TreeModel
);
}
static void ProcessItems<T>(Process process, Dispatcher dispatcher, int startIndex, IList<T> items, Action<T> work, DebuggeeState debuggeeStateWhenEnqueued)
static void ProcessItems<T>(Process process, Dispatcher dispatcher, int startIndex, IList<T> items, Action<T> work, long debuggeeStateWhenEnqueued)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
@ -122,9 +122,9 @@ namespace Debugger.AddIn.TreeModel @@ -122,9 +122,9 @@ namespace Debugger.AddIn.TreeModel
public static class ExtensionMethods
{
public static TreeNodeWrapper ToSharpTreeNode(this TreeNode node)
public static SharpTreeNodeAdapter ToSharpTreeNode(this TreeNode node)
{
return new TreeNodeWrapper(node);
return new SharpTreeNodeAdapter(node);
}
}
}

478
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs

@ -0,0 +1,478 @@ @@ -0,0 +1,478 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Debugger.AddIn.Visualizers;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui.Pads;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// Tree node which represents debuggee's <see cref="Value"/>.
/// The node stores a lambda which can be used to reobtain the value
/// at any time (possibly even after some stepping).
/// </summary>
/// <remarks>
/// The general rule is that getting a value or getting children will
/// either succeed or result in <see cref="GetValueException"/>.
/// </remarks>
public class ValueNode: TreeNode
{
Func<Value> getValue;
Action<Value> setValue;
Value cachedValue;
Debugger.Process cachedValueProcess;
long cachedValueDebuggeeState;
string fullValue;
GetValueException error;
public string FullText {
get { return this.Value; }
}
public ValueNode(string imageName, string name, Func<Value> getValue, Action<Value> setValue = null)
: base(imageName, name, string.Empty, string.Empty, null)
{
if (getValue == null)
throw new ArgumentNullException("getValue");
this.getValue = getValue;
this.setValue = setValue;
GetValueAndUpdateUI();
}
/// <summary>
/// Get the value of the node and cache it as long-lived reference.
/// We assume that the user will need this value a lot.
/// </summary>
public Value GetValue()
{
// The value still survives across debuggee state, but we want a fresh one for the UI
if (cachedValue == null || cachedValueProcess.DebuggeeState != cachedValueDebuggeeState)
{
Stopwatch watch = new Stopwatch();
watch.Start();
cachedValue = this.getValue().GetPermanentReference(WindowsDebugger.EvalThread);
cachedValueProcess = cachedValue.Process;
cachedValueDebuggeeState = cachedValue.Process.DebuggeeState;
LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms (result cached for future use)", this.Name, watch.ElapsedMilliseconds);
}
return cachedValue;
}
public void SetValue(Value value)
{
if (setValue == null)
throw new DebuggerException("Setting of value is not supported for this node");
try
{
this.setValue(value);
}
catch(GetValueException e)
{
MessageService.ShowMessage(e.Message, "${res:MainWindow.Windows.Debug.LocalVariables.CannotSetValue.Title}");
}
}
/// <summary>
/// Get the value of the node and update the UI text fields.
/// </summary>
void GetValueAndUpdateUI()
{
try {
Stopwatch watch = new Stopwatch();
watch.Start();
// Do not keep permanent reference
Value val = this.getValue();
// Note that the child collections are lazy-evaluated
if (val.IsNull) {
this.GetChildren = null;
} else if (val.Type.IsPrimitive || val.Type.FullName == typeof(string).FullName) { // Must be before IsClass
this.GetChildren = null;
} else if (val.Type.IsArray) { // Must be before IsClass
var dims = val.ArrayDimensions; // Eval now
if (dims.TotalElementCount > 0) {
this.GetChildren = () => GetArrayChildren(dims, dims);
}
} else if (val.Type.IsClass || val.Type.IsValueType) {
if (val.Type.FullNameWithoutGenericArguments == typeof(List<>).FullName) {
if ((int)val.GetFieldValue("_size").PrimitiveValue > 0)
this.GetChildren = () => GetIListChildren(this.GetValue);
} else {
this.GetChildren = () => GetObjectChildren(val.Type);
}
} else if (val.Type.IsPointer) {
if (val.Dereference() != null) {
this.GetChildren = () => new[] { new ValueNode("Icons.16x16.Local", "*" + this.Name, () => GetValue().Dereference()) };
}
}
// Do last since it may expire the object
if (val.IsNull) {
fullValue = "null";
} else if (val.Type.IsInteger) {
var i = val.PrimitiveValue;
if (DebuggingOptions.Instance.ShowIntegersAs == ShowIntegersAs.Decimal) {
fullValue = i.ToString();
} else {
string hex = string.Format("0x{0:X4}", i);
if (hex.Length > 6 ) hex = string.Format("0x{0:X8}", i);
if (hex.Length > 10) hex = string.Format("0x{0:X16}", i);
if (DebuggingOptions.Instance.ShowIntegersAs == ShowIntegersAs.Hexadecimal) {
fullValue = hex;
} else {
fullValue = string.Format("{0} ({1})", i, hex);
}
}
} else if (val.Type.IsPointer) {
fullValue = String.Format("0x{0:X}", val.PointerAddress);
} else if (val.Type.FullName == typeof(string).FullName) {
fullValue = '"' + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + '"';
} else if (val.Type.FullName == typeof(char).FullName) {
fullValue = "'" + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + "'";
} else if ((val.Type.IsClass || val.Type.IsValueType)) {
fullValue = val.InvokeToString(WindowsDebugger.EvalThread);
} else {
fullValue = val.AsString();
}
this.error = null;
this.Value = (fullValue.Length > 256) ? fullValue.Substring(0, 256) + "..." : fullValue;
this.Type = val.Type.Name;
if (!val.IsNull) {
this.VisualizerCommands = VisualizerDescriptors.GetAllDescriptors()
.Where(descriptor => descriptor.IsVisualizerAvailable(val.Type))
.Select(descriptor => descriptor.CreateVisualizerCommand(this.Name, this.GetValue))
.ToList();
}
LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms", this.Name, watch.ElapsedMilliseconds);
} catch (GetValueException e) {
error = e;
this.Value = e.Message;
this.Type = string.Empty;
this.GetChildren = null;
this.VisualizerCommands = null;
return;
}
}
// public ContextMenuStrip GetContextMenu()
// {
// if (this.Error != null) return GetErrorContextMenu();
//
// ContextMenuStrip menu = new ContextMenuStrip();
//
// ToolStripMenuItem copyItem;
// copyItem = new ToolStripMenuItem();
// copyItem.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.CopyToClipboard");
// copyItem.Checked = false;
// copyItem.Click += delegate {
// ClipboardWrapper.SetText(fullText);
// };
// ToolStripMenuItem hexView;
// hexView = new ToolStripMenuItem();
// hexView.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.ShowInHexadecimal");
// hexView.Checked = DebuggingOptions.Instance.ShowValuesInHexadecimal;
// hexView.Click += delegate {
// // refresh all pads that use ValueNode for display
// DebuggingOptions.Instance.ShowValuesInHexadecimal = !DebuggingOptions.Instance.ShowValuesInHexadecimal;
// // always check if instance is null, might be null if pad is not opened
// if (LocalVarPad.Instance != null)
// LocalVarPad.Instance.RefreshPad();
// if (WatchPad.Instance != null)
// WatchPad.Instance.RefreshPad();
// };
// menu.Items.AddRange(new ToolStripItem[] {
// copyItem,
// //hexView
// });
//
// return menu;
// }
ContextMenuStrip GetErrorContextMenu()
{
ContextMenuStrip menu = new ContextMenuStrip();
ToolStripMenuItem showError = new ToolStripMenuItem();
showError.Text = StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.ShowFullError}");
showError.Click += delegate { MessageService.ShowException(error, null); };
menu.Items.Add(showError);
return menu;
}
public static string GetImageForMember(IDebugMemberInfo memberInfo)
{
string name = string.Empty;
if (memberInfo.IsPublic) {
} else if (memberInfo.IsAssembly) {
name += "Internal";
} else if (memberInfo.IsFamily) {
name += "Protected";
} else if (memberInfo.IsPrivate) {
name += "Private";
}
if (memberInfo is FieldInfo) {
name += "Field";
} else if (memberInfo is PropertyInfo) {
name += "Property";
} else if (memberInfo is MethodInfo) {
name += "Method";
} else {
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
return "Icons.16x16." + name;
}
/// <summary>
/// The root of any node evaluation is valid stack frame.
/// </summary>
static StackFrame GetCurrentStackFrame()
{
if (WindowsDebugger.CurrentProcess == null)
throw new GetValueException("Debugger is not running");
if (WindowsDebugger.CurrentProcess.IsRunning)
throw new GetValueException("Process is not paused");
if (WindowsDebugger.CurrentStackFrame == null)
throw new GetValueException("No stack frame selected");
return WindowsDebugger.CurrentStackFrame;
}
public static IEnumerable<TreeNode> GetLocalVariables()
{
var stackFrame = GetCurrentStackFrame();
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
var parCopy = par;
yield return new ValueNode("Icons.16x16.Parameter", par.Name, () => parCopy.GetValue(GetCurrentStackFrame()));
}
if (stackFrame.HasSymbols) {
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(stackFrame.IP)) {
var locVarCopy = locVar;
yield return new ValueNode("Icons.16x16.Local", locVar.Name, () => locVarCopy.GetValue(GetCurrentStackFrame()));
}
} else {
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
if (debugger.debuggerDecompilerService != null) {
int typeToken = stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = stackFrame.MethodInfo.MetadataToken;
foreach (var localVar in debugger.debuggerDecompilerService.GetLocalVariables(typeToken, methodToken)) {
int index = ((int[])debugger.debuggerDecompilerService.GetLocalVariableIndex(typeToken, methodToken, localVar))[0];
yield return new ValueNode("Icons.16x16.Local", localVar, () => {
var newStackFrame = GetCurrentStackFrame();
if (newStackFrame.MethodInfo != stackFrame.MethodInfo)
throw new GetValueException("Expected stack frame: " + stackFrame.MethodInfo.ToString());
return newStackFrame.GetLocalVariableValue((uint)index);
});
}
}
}
}
IEnumerable<TreeNode> GetObjectChildren(DebugType shownType)
{
MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
DebugType baseType = (DebugType)shownType.BaseType;
if (baseType != null) {
yield return new TreeNode(
"Icons.16x16.Class",
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.BaseClass}"),
baseType.Name,
baseType.FullName,
baseType.FullName == "System.Object" ? (Func<IEnumerable<TreeNode>>) null : () => GetObjectChildren(baseType)
);
}
if (nonPublicInstance.Length > 0) {
yield return new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicMembers}"),
() => GetMembers(nonPublicInstance)
);
}
if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) {
yield return new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.StaticMembers}"),
() => {
var children = GetMembers(publicStatic).ToList();
if (nonPublicStatic.Length > 0) {
children.Insert(0, new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicStaticMembers}"),
() => GetMembers(nonPublicStatic)
));
}
return children;
}
);
}
if (shownType.GetInterface(typeof(IList).FullName) != null) {
yield return new TreeNode(
"IList",
() => GetIListChildren(GetValue)
);
} else {
DebugType iEnumerableType, itemType;
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
yield return new TreeNode(
null,
"IEnumerable",
"Expanding will enumerate the IEnumerable",
string.Empty,
() => GetIListChildren(() => DebuggerHelpers.CreateListFromIEnumerable(GetValue()))
);
}
}
foreach(TreeNode node in GetMembers(publicInstance)) {
yield return node;
}
}
IEnumerable<TreeNode> GetMembers(MemberInfo[] members)
{
foreach(MemberInfo memberInfo in members.OrderBy(m => m.Name)) {
var memberInfoCopy = memberInfo;
string imageName = GetImageForMember((IDebugMemberInfo)memberInfo);
yield return new ValueNode(imageName, memberInfo.Name, () => GetValue().GetMemberValue(WindowsDebugger.EvalThread, memberInfoCopy));
}
}
static IEnumerable<TreeNode> GetIListChildren(Func<Value> getValue)
{
Value list;
PropertyInfo itemProp;
int count = 0;
try {
// TODO: We want new list on reeval
// We need the list to survive generation of index via Eval
list = getValue().GetPermanentReference(WindowsDebugger.EvalThread);
DebugType iListType = (DebugType)list.Type.GetInterface(typeof(IList).FullName);
itemProp = iListType.GetProperty("Item");
// Do not get string representation since it can be printed in hex
count = (int)list.GetPropertyValue(WindowsDebugger.EvalThread, iListType.GetProperty("Count")).PrimitiveValue;
} catch (GetValueException e) {
return new [] { new TreeNode(null, "(error)", e.Message, string.Empty, null) };
}
if (count == 0) {
return new [] { new TreeNode("(empty)", null) };
} else {
return Enumerable.Range(0, count).Select(i => new ValueNode("Icons.16x16.Field", "[" + i + "]", () => list.GetPropertyValue(WindowsDebugger.EvalThread, itemProp, Eval.CreateValue(WindowsDebugger.EvalThread, i))));
}
}
TreeNode GetArraySubsetNode(ArrayDimensions bounds, ArrayDimensions originalBounds)
{
StringBuilder name = new StringBuilder();
bool isFirst = true;
name.Append("[");
for(int i = 0; i < bounds.Count; i++) {
if (!isFirst) name.Append(", ");
isFirst = false;
ArrayDimension dim = bounds[i];
ArrayDimension originalDim = originalBounds[i];
if (dim.Count == 0) {
name.Append("-");
} else if (dim.Count == 1) {
name.Append(dim.LowerBound.ToString());
} else if (dim.Equals(originalDim)) {
name.Append("*");
} else {
name.Append(dim.LowerBound);
name.Append("..");
name.Append(dim.UpperBound);
}
}
name.Append("]");
return new TreeNode(name.ToString(), () => GetArrayChildren(bounds, originalBounds));
}
IEnumerable<TreeNode> GetArrayChildren(ArrayDimensions bounds, ArrayDimensions originalBounds)
{
const int MaxElementCount = 1000;
if (bounds.TotalElementCount == 0)
{
yield return new TreeNode("(empty)", null);
yield break;
}
// The whole array is small - just add all elements as childs
if (bounds.TotalElementCount <= MaxElementCount * 2) {
foreach(int[] indices in bounds.Indices) {
StringBuilder sb = new StringBuilder(indices.Length * 4);
sb.Append("[");
bool isFirst = true;
foreach(int index in indices) {
if (!isFirst) sb.Append(", ");
sb.Append(index.ToString());
isFirst = false;
}
sb.Append("]");
int[] indicesCopy = indices;
yield return new ValueNode("Icons.16x16.Field", sb.ToString(), () => GetValue().GetArrayElement(indicesCopy));
}
yield break;
}
// Find a dimension of size at least 2
int splitDimensionIndex = bounds.Count - 1;
for(int i = 0; i < bounds.Count; i++) {
if (bounds[i].Count > 1) {
splitDimensionIndex = i;
break;
}
}
ArrayDimension splitDim = bounds[splitDimensionIndex];
// Split the dimension
int elementsPerSegment = 1;
while (splitDim.Count > elementsPerSegment * MaxElementCount) {
elementsPerSegment *= MaxElementCount;
}
for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) {
List<ArrayDimension> newDims = new List<ArrayDimension>(bounds);
newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound));
yield return GetArraySubsetNode(new ArrayDimensions(newDims), originalBounds);
}
yield break;
}
}
}

10
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs

@ -16,11 +16,15 @@ namespace Debugger.AddIn.Visualizers @@ -16,11 +16,15 @@ namespace Debugger.AddIn.Visualizers
// should we make visualizer command available for Expression, or any TreeNode?
public abstract class ExpressionVisualizerCommand : IVisualizerCommand
{
public Expression Expression { get; private set; }
public string ValueName { get; private set; }
public Func<Value> GetValue { get; private set; }
public ExpressionVisualizerCommand(Expression expression)
public ExpressionVisualizerCommand(string valueName, Func<Value> getValue)
{
this.Expression = expression;
if (getValue == null)
throw new ArgumentNullException("getValue");
this.ValueName = valueName;
this.GetValue = getValue;
}
public abstract void Execute();

13
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs

@ -25,9 +25,9 @@ namespace Debugger.AddIn.Visualizers @@ -25,9 +25,9 @@ namespace Debugger.AddIn.Visualizers
return type.ResolveIEnumerableImplementation(out collectionType, out itemType);
}
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
{
return new GridVisualizerCommand(expression);
return new GridVisualizerCommand(valueName, getValue);
}
}
@ -36,8 +36,7 @@ namespace Debugger.AddIn.Visualizers @@ -36,8 +36,7 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class GridVisualizerCommand : ExpressionVisualizerCommand
{
public GridVisualizerCommand(Expression expression)
:base(expression)
public GridVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
{
}
@ -48,10 +47,8 @@ namespace Debugger.AddIn.Visualizers @@ -48,10 +47,8 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
if (this.Expression == null)
return;
var gridVisualizerWindow = GridVisualizerWindow.EnsureShown();
gridVisualizerWindow.ShownExpression = this.Expression;
GridVisualizerWindow window = new GridVisualizerWindow(this.ValueName, this.GetValue);
window.ShowDialog();
}
}
}

4
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs

@ -14,9 +14,7 @@ namespace Debugger.AddIn.Visualizers @@ -14,9 +14,7 @@ namespace Debugger.AddIn.Visualizers
{
public override void Run()
{
GridVisualizerWindow window = new GridVisualizerWindow();
window.Topmost = true;
window.Show();
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs

@ -16,6 +16,6 @@ namespace Debugger.AddIn.Visualizers @@ -16,6 +16,6 @@ namespace Debugger.AddIn.Visualizers
public interface IVisualizerDescriptor
{
bool IsVisualizerAvailable(DebugType type);
IVisualizerCommand CreateVisualizerCommand(Expression expression);
IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue);
}
}

11
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs

@ -21,9 +21,9 @@ namespace Debugger.AddIn.Visualizers @@ -21,9 +21,9 @@ namespace Debugger.AddIn.Visualizers
return !type.IsAtomic() && !type.IsSystemDotObject();
}
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
{
return new ObjectGraphVisualizerCommand(expression);
return new ObjectGraphVisualizerCommand(valueName, getValue);
}
}
@ -32,8 +32,7 @@ namespace Debugger.AddIn.Visualizers @@ -32,8 +32,7 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class ObjectGraphVisualizerCommand : ExpressionVisualizerCommand
{
public ObjectGraphVisualizerCommand(Expression expression)
:base(expression)
public ObjectGraphVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
{
}
@ -44,10 +43,8 @@ namespace Debugger.AddIn.Visualizers @@ -44,10 +43,8 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
if (this.Expression == null)
return;
var objectGraphWindow = ObjectGraphWindow.EnsureShown();
objectGraphWindow.ShownExpression = this.Expression;
objectGraphWindow.ShownExpression = new GraphExpression(new IdentifierExpression(this.ValueName), this.GetValue);
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs

@ -20,16 +20,15 @@ namespace Debugger.AddIn.Visualizers @@ -20,16 +20,15 @@ namespace Debugger.AddIn.Visualizers
return type.FullName == typeof(string).FullName;
}
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
{
return new TextVisualizerCommand(expression);
return new TextVisualizerCommand(valueName, getValue);
}
}
public class TextVisualizerCommand : ExpressionVisualizerCommand
{
public TextVisualizerCommand(Expression expression)
:base(expression)
public TextVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
{
}
@ -40,10 +39,7 @@ namespace Debugger.AddIn.Visualizers @@ -40,10 +39,7 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
if (this.Expression == null)
return;
string expressionValue = this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString();
var textVisualizerWindow = new TextVisualizerWindow(this.Expression.PrettyPrint(), expressionValue);
var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString());
textVisualizerWindow.ShowDialog();
}
}

13
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs

@ -20,9 +20,9 @@ namespace Debugger.AddIn.Visualizers @@ -20,9 +20,9 @@ namespace Debugger.AddIn.Visualizers
return type.FullName == typeof(string).FullName;
}
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
{
return new XmlVisualizerCommand(expression);
return new XmlVisualizerCommand(valueName, getValue);
}
}
@ -31,8 +31,7 @@ namespace Debugger.AddIn.Visualizers @@ -31,8 +31,7 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class XmlVisualizerCommand : ExpressionVisualizerCommand
{
public XmlVisualizerCommand(Expression expression)
:base(expression)
public XmlVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
{
}
@ -43,11 +42,7 @@ namespace Debugger.AddIn.Visualizers @@ -43,11 +42,7 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
if (this.Expression == null)
return;
var textVisualizerWindow = new TextVisualizerWindow(
this.Expression.PrettyPrint(), this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString());
textVisualizerWindow.Mode = TextVisualizerMode.Xml;
var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString(), ".xml");
textVisualizerWindow.ShowDialog();
}
}

16
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs

@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// Can provide individial items for a lazy collection, as well as total count of items.
/// </summary>
public interface IListValuesProvider<T>
{
int GetCount();
T GetItemAt(int index);
}
}

0
src/Main/Base/Project/Src/Services/Debugger/Tooltips/IVisualizerCommand.cs → src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IVisualizerCommand.cs

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/ObjectProperty.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using Debugger.AddIn.Visualizers.Graph;
using ICSharpCode.NRefactory.Ast;
namespace Debugger.AddIn.Visualizers
@ -24,7 +25,7 @@ namespace Debugger.AddIn.Visualizers @@ -24,7 +25,7 @@ namespace Debugger.AddIn.Visualizers
/// <summary>
/// Expression used for obtaining value of this property
/// </summary>
public Expression Expression { get; set; }
public GraphExpression Expression { get; set; }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)

16
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs

@ -8,21 +8,23 @@ using System.Collections.Generic; @@ -8,21 +8,23 @@ using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// IList&lt;T&gt; with data vitualization - the indexer is lazy, uses IListValuesProvider to obtain values when needed.
/// IList&lt;T&gt; with data vitualization - the indexer is lazy, uses lamda function to obtain values when needed.
/// </summary>
public class VirtualizingCollection<T> : IList<T>, IList
{
private IListValuesProvider<T> valueProvider;
private Dictionary<int, T> itemCache = new Dictionary<int, T>();
int count;
Func<int, T> getItem;
Dictionary<int, T> itemCache = new Dictionary<int, T>();
public VirtualizingCollection(IListValuesProvider<T> valueProvider)
public VirtualizingCollection(int count, Func<int, T> getItem)
{
this.valueProvider = valueProvider;
this.count = count;
this.getItem = getItem;
}
public int Count
{
get { return this.valueProvider.GetCount(); }
get { return count; }
}
public T this[int index]
@ -32,7 +34,7 @@ namespace Debugger.AddIn.Visualizers @@ -32,7 +34,7 @@ namespace Debugger.AddIn.Visualizers
T cachedItem;
if (!itemCache.TryGetValue(index, out cachedItem))
{
cachedItem = this.valueProvider.GetItemAt(index);
cachedItem = getItem(index);
this.itemCache[index] = cachedItem;
}
return cachedItem;

28
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/GraphExpression.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
// 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.Linq;
using ICSharpCode.NRefactory.Ast;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// NRefactory Expression plus a method that can evaluate it,
/// as the Debugger does not support evaluating NRefactory expressions directly.
/// </summary>
public class GraphExpression
{
public Expression Expr { get; set; }
public Func<Value> GetValue { get; set; }
public GraphExpression(Expression expr, Func<Value> getValue)
{
if (expr == null) throw new ArgumentNullException("expr");
if (getValue == null) throw new ArgumentNullException("getValue");
this.Expr = expr;
this.GetValue = getValue;
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/PositionedNodeProperty.cs

@ -70,7 +70,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -70,7 +70,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <summary>
/// Full Debugger expression used to obtain value of this property.
/// </summary>
public Expression Expression { get { return this.objectGraphProperty.Expression; } }
public GraphExpression Expression { get { return this.objectGraphProperty.Expression; } }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentNode.cs

@ -36,7 +36,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -36,7 +36,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public string FullPath
{
get { return this.containingNode.ObjectNode.Expression.PrettyPrint() + "/" + this.Path; }
get { return this.containingNode.ObjectNode.Expression.Expr.PrettyPrint() + "/" + this.Path; }
}
private ContentNode parent;

6
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs

@ -6,6 +6,7 @@ using System.ComponentModel; @@ -6,6 +6,7 @@ using System.ComponentModel;
using Debugger.AddIn.TreeModel;
using Debugger.AddIn.Visualizers.Graph.Drawing;
using Debugger.MetaData;
using ICSharpCode.SharpDevelop;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
@ -65,7 +66,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -65,7 +66,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
this.IsExpanded = false; // always false, Property nodes are never expanded (they have IsPropertyExpanded)
this.Property = new PositionedNodeProperty(
sourcePropertyNode.Property, this.ContainingNode,
expanded.Expressions.IsExpanded(sourcePropertyNode.Property.Expression));
expanded.Expressions.IsExpanded(sourcePropertyNode.Property.Expression.Expr));
if (PositionedGraphNodeControl.IsShowMemberIcon) {
EvalMemberIcon();
}
@ -77,8 +78,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -77,8 +78,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
if ((this.Property != null) && (this.Property.ObjectGraphProperty != null)) {
var memberInfo = (IDebugMemberInfo)this.Property.ObjectGraphProperty.MemberInfo;
if (memberInfo != null) {
string imageName;
var image = ExpressionNode.GetImageForMember(memberInfo, out imageName);
var image = new ResourceServiceImage(ValueNode.GetImageForMember(memberInfo));
this.MemberIcon = image.ImageSource;
}
}

86
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs

@ -79,26 +79,20 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -79,26 +79,20 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="expression">Expression valid in the program being debugged (eg. variable name)</param>
/// <returns>Object graph</returns>
public ObjectGraph BuildGraphForExpression(string expression, ExpandedExpressions expandedNodes)
public ObjectGraph BuildGraphForExpression(GraphExpression expression, ExpandedExpressions expandedNodes)
{
if (string.IsNullOrEmpty(expression)) {
throw new DebuggerVisualizerException("Please specify an expression.");
}
var debuggedProcess = this.debuggerService.DebuggedProcess;
if (debuggedProcess == null || debuggedProcess.IsRunning || debuggedProcess.SelectedStackFrame == null) {
if (WindowsDebugger.CurrentStackFrame == null) {
throw new DebuggerVisualizerException("Please use the visualizer when debugging.");
}
var rootExpression = ExpressionEvaluator.ParseExpression(expression, SupportedLanguage.CSharp);
Value rootValue = rootExpression.Evaluate(debuggedProcess);
Value rootValue = expression.GetValue();
if (rootValue.IsNull) {
throw new DebuggerVisualizerException(expression + " is null.");
}
return buildGraphForValue(rootValue.GetPermanentReference(), rootExpression, expandedNodes);
return buildGraphForValue(rootValue.GetPermanentReference(WindowsDebugger.EvalThread), expression, expandedNodes);
}
private ObjectGraph buildGraphForValue(Value rootValue, Expression rootExpression, ExpandedExpressions expandedNodes)
private ObjectGraph buildGraphForValue(Value rootValue, GraphExpression rootExpression, ExpandedExpressions expandedNodes)
{
resultGraph = new ObjectGraph();
//resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference(), expandedNodes);
@ -108,15 +102,15 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -108,15 +102,15 @@ namespace Debugger.AddIn.Visualizers.Graph
return resultGraph;
}
public ObjectGraphNode ObtainNodeForExpression(Expression expr)
public ObjectGraphNode ObtainNodeForExpression(GraphExpression expr)
{
bool createdNewNode; // ignored (caller is not interested, otherwise he would use the other overload)
return ObtainNodeForExpression(expr, out createdNewNode);
}
public ObjectGraphNode ObtainNodeForExpression(Expression expr, out bool createdNewNode)
public ObjectGraphNode ObtainNodeForExpression(GraphExpression expr, out bool createdNewNode)
{
return ObtainNodeForValue(expr.EvalPermanentReference(), expr, out createdNewNode);
return ObtainNodeForValue(expr.GetValue().GetPermanentReference(WindowsDebugger.EvalThread), expr, out createdNewNode);
}
/// <summary>
@ -124,7 +118,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -124,7 +118,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="value">Value for which to obtain the node/</param>
/// <param name="createdNew">True if new node was created, false if existing node was returned.</param>
public ObjectGraphNode ObtainNodeForValue(Value value, Expression expression, out bool createdNew)
public ObjectGraphNode ObtainNodeForValue(Value value, GraphExpression expression, out bool createdNew)
{
createdNew = false;
ObjectGraphNode nodeForValue = getExistingNodeForValue(value);
@ -158,7 +152,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -158,7 +152,10 @@ namespace Debugger.AddIn.Visualizers.Graph
//AddRawViewNode(contentRoot, thisNode);
// it is an IEnumerable
DebugType debugListType;
var debugListExpression = DebuggerHelpers.CreateDebugListExpression(thisNode.Expression, itemType, out debugListType);
var debugListExpression = new GraphExpression(
DebuggerHelpers.CreateDebugListExpression(thisNode.Expression.Expr, itemType, out debugListType),
() => DebuggerHelpers.CreateListFromIEnumerable(thisNode.Expression.GetValue())
);
LoadNodeCollectionContent(contentRoot, debugListExpression, debugListType);
} else {
// it is an object
@ -173,21 +170,26 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -173,21 +170,26 @@ namespace Debugger.AddIn.Visualizers.Graph
LoadNodeObjectContent(rawViewNode, thisNode.Expression, thisNode.PermanentReference.Type);
}
void LoadNodeCollectionContent(AbstractNode node, Expression thisObject, DebugType iListType)
void LoadNodeCollectionContent(AbstractNode node, GraphExpression thisObject, DebugType iListType)
{
thisObject = thisObject.CastToIList();
int listCount = thisObject.GetIListCount();
var thisObjectAsIList = new GraphExpression(thisObject.Expr.CastToIList(), thisObject.GetValue);
int listCount = thisObjectAsIList.GetValue().GetIListCount();
PropertyInfo indexerProp = iListType.GetProperty("Item");
var v = new List<String>();
for (int i = 0; i < listCount; i++) {
Expression itemExpr = thisObject.AppendIndexer(i);
var itemExpr = new GraphExpression(
thisObjectAsIList.Expr.AppendIndexer(i),
() => thisObjectAsIList.GetValue().GetIListItem(i) // EXPR-EVAL, Does a 'cast' to IList
);
PropertyNode itemNode = new PropertyNode(
new ObjectGraphProperty { Name = "[" + i + "]", MemberInfo = indexerProp, Expression = itemExpr, Value = "", IsAtomic = true, TargetNode = null });
node.AddChild(itemNode);
}
}
void LoadNodeObjectContent(AbstractNode node, Expression expression, DebugType type)
void LoadNodeObjectContent(AbstractNode node, GraphExpression expression, DebugType type)
{
// base
if (type.BaseType != null && type.BaseType.FullName != "System.Object")
@ -216,7 +218,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -216,7 +218,7 @@ namespace Debugger.AddIn.Visualizers.Graph
}
}
private List<ObjectGraphProperty> getProperties(Expression expression, DebugType shownType, BindingFlags flags)
private List<ObjectGraphProperty> getProperties(GraphExpression expression, DebugType shownType, BindingFlags flags)
{
List<ObjectGraphProperty> propertyList = new List<ObjectGraphProperty>();
@ -233,7 +235,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -233,7 +235,10 @@ namespace Debugger.AddIn.Visualizers.Graph
// ObjectGraphProperty needs an expression
// to know whether it is expanded, and to evaluate
Expression propExpression = expression.AppendMemberReference((IDebugMemberInfo)memberProp);
var propExpression = new GraphExpression(
expression.Expr.AppendMemberReference((IDebugMemberInfo)memberProp),
() => expression.GetValue().GetMemberValue(WindowsDebugger.EvalThread, memberProp) // EXPR-EVAL
);
// Value, IsAtomic are lazy evaluated
propertyList.Add(new ObjectGraphProperty
{ Name = memberProp.Name,
@ -258,10 +263,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -258,10 +263,10 @@ namespace Debugger.AddIn.Visualizers.Graph
// We are only evaluating expanded nodes here.
// We have to do this to know the "shape" of the graph.
// We do not evaluate atomic and non-expanded properties, those will be lazy evaluated when drawn.
if (expandedNodes.IsExpanded(complexProperty.Expression))
if (expandedNodes.IsExpanded(complexProperty.Expression.Expr))
{
// if expanded, evaluate this property
Value memberValue = complexProperty.Expression.Evaluate(this.debuggerService.DebuggedProcess);
Value memberValue = complexProperty.Expression.GetValue();
if (memberValue.IsNull)
{
continue;
@ -269,7 +274,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -269,7 +274,7 @@ namespace Debugger.AddIn.Visualizers.Graph
else
{
// if property value is not null, create neighbor
memberValue = memberValue.GetPermanentReference();
memberValue = memberValue.GetPermanentReference(WindowsDebugger.EvalThread);
bool createdNew;
// get existing node (loop) or create new
@ -295,7 +300,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -295,7 +300,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="permanentReference">Value, has to be valid.</param>
/// <returns>New empty object node representing the value.</returns>
private ObjectGraphNode createNewNode(Value permanentReference, Expression expression)
private ObjectGraphNode createNewNode(Value permanentReference, GraphExpression expression)
{
if (permanentReference == null) throw new ArgumentNullException("permanentReference");
@ -341,32 +346,5 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -341,32 +346,5 @@ namespace Debugger.AddIn.Visualizers.Graph
return nodeWithSameAddress;
}
}
public ObjectGraphProperty createAtomicProperty(string name, Expression expression)
{
// value is empty (will be lazy-evaluated later)
return new ObjectGraphProperty
{ Name = name, Value = "", Expression = expression, IsAtomic = true, TargetNode = null };
}
public ObjectGraphProperty createComplexProperty(string name, Expression expression, ObjectGraphNode targetNode, bool isNull)
{
// value is empty (will be lazy-evaluated later)
return new ObjectGraphProperty
{ Name = name, Value = "", Expression = expression, IsAtomic = false, TargetNode = targetNode, IsNull = isNull };
}
/// <summary>
/// Checks whether given expression's type is supported by the graph builder.
/// </summary>
/// <param name="expr">Expression to be checked.</param>
private void checkIsOfSupportedType(Expression expr)
{
DebugType typeOfValue = expr.Evaluate(debuggerService.DebuggedProcess).Type;
if (typeOfValue.IsArray)
{
throw new DebuggerVisualizerException("Arrays are not supported yet");
}
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphNode.cs

@ -27,7 +27,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -27,7 +27,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <summary>
/// Expression used to obtain this node.
/// </summary>
public Expression Expression { get; set; }
public GraphExpression Expression { get; set; }
/// <summary>
/// Property tree of this node.

4
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphProperty.cs

@ -39,7 +39,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -39,7 +39,7 @@ namespace Debugger.AddIn.Visualizers.Graph
if (this.Expression == null) throw new DebuggerVisualizerException("Cannot evaluate property with missing Expression");
Value debuggerVal;
try {
debuggerVal = this.Expression.Evaluate(WindowsDebugger.CurrentProcess);
debuggerVal = this.Expression.GetValue();
} catch (System.Exception ex) {
this.Value = "Exception: " + ex.Message;
this.IsEvaluated = true;
@ -49,7 +49,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -49,7 +49,7 @@ namespace Debugger.AddIn.Visualizers.Graph
this.IsAtomic = debuggerVal.Type.IsAtomic();
this.IsNull = debuggerVal.IsNull;
// null and complex properties will show empty string
this.Value = debuggerVal.IsNull || (!this.IsAtomic) ? string.Empty : debuggerVal.InvokeToString();
this.Value = debuggerVal.IsNull || (!this.IsAtomic) ? string.Empty : debuggerVal.InvokeToString(WindowsDebugger.EvalThread);
this.IsEvaluated = true;
}
}

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphControl.xaml

@ -25,8 +25,7 @@ @@ -25,8 +25,7 @@
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">Expression:</TextBlock>
<TextBox Name="txtExpression" VerticalAlignment="Center" Width="100"></TextBox>
<Button Click="Inspect_Button_Click">Inspect</Button>
<TextBlock Margin="12 0 6 0" VerticalAlignment="Center">Layout:</TextBlock>
<TextBlock Margin="12 0 6 0" VerticalAlignment="Center">Layout:</TextBlock>
<ComboBox Name="cmbLayoutDirection" Width="120" ItemsSource="{Binding Path=EnumValues}" SelectedValue="{Binding Path=SelectedEnumValue}" SelectedValuePath="EnumValue" DisplayMemberPath="DisplayValue"></ComboBox>
<TextBlock Margin="12 0 6 0" VerticalAlignment="Center">Zoom:</TextBlock>
<Slider x:Name="zoomSlider" Width="100" Minimum="0.5" Maximum="1" Value="1"/>

26
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphControl.xaml.cs

@ -62,7 +62,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -62,7 +62,7 @@ namespace Debugger.AddIn.Visualizers.Graph
public void RefreshView()
{
debuggerService.DebuggedProcess.EnqueueWork(Dispatcher, () => Refresh());
WindowsDebugger.CurrentProcess.EnqueueWork(Dispatcher, () => Refresh());
}
void Refresh()
@ -78,7 +78,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -78,7 +78,7 @@ namespace Debugger.AddIn.Visualizers.Graph
}
bool isSuccess = true;
try {
this.objectGraph = RebuildGraph(txtExpression.Text);
this.objectGraph = RebuildGraph();
} catch(DebuggerVisualizerException ex) {
isSuccess = false;
ErrorMessage(ex.Message);
@ -94,8 +94,8 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -94,8 +94,8 @@ namespace Debugger.AddIn.Visualizers.Graph
}
}
private ICSharpCode.NRefactory.Ast.Expression shownExpression;
public ICSharpCode.NRefactory.Ast.Expression ShownExpression
private GraphExpression shownExpression;
public GraphExpression ShownExpression
{
get {
return shownExpression;
@ -107,23 +107,17 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -107,23 +107,17 @@ namespace Debugger.AddIn.Visualizers.Graph
RefreshView();
return;
}
if (shownExpression == null || value.PrettyPrint() != shownExpression.PrettyPrint()) {
txtExpression.Text = value.PrettyPrint();
if (shownExpression == null || value.Expr.PrettyPrint() != shownExpression.Expr.PrettyPrint()) {
txtExpression.Text = value.Expr.PrettyPrint();
RefreshView();
}
}
}
private void Inspect_Button_Click(object sender, RoutedEventArgs e)
{
RefreshView();
}
ObjectGraph RebuildGraph(string expression)
ObjectGraph RebuildGraph()
{
this.objectGraphBuilder = new ObjectGraphBuilder(debuggerService);
Log.Debug("Debugger visualizer: Building graph for expression: " + txtExpression.Text);
return this.objectGraphBuilder.BuildGraphForExpression(expression, expanded.Expressions);
return this.objectGraphBuilder.BuildGraphForExpression(this.ShownExpression, expanded.Expressions);
}
void LayoutGraph(ObjectGraph graph)
@ -185,7 +179,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -185,7 +179,7 @@ namespace Debugger.AddIn.Visualizers.Graph
void node_PropertyExpanded(object sender, PositionedPropertyEventArgs e)
{
// remember this property is expanded (for later graph rebuilds)
expanded.Expressions.SetExpanded(e.Property.Expression);
expanded.Expressions.SetExpanded(e.Property.Expression.Expr);
// add edge (+ possibly nodes) to underlying object graph (no need to fully rebuild)
e.Property.ObjectGraphProperty.TargetNode = this.objectGraphBuilder.ObtainNodeForExpression(e.Property.Expression);
@ -195,7 +189,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -195,7 +189,7 @@ namespace Debugger.AddIn.Visualizers.Graph
void node_PropertyCollapsed(object sender, PositionedPropertyEventArgs e)
{
// remember this property is collapsed (for later graph rebuilds)
expanded.Expressions.SetCollapsed(e.Property.Expression);
expanded.Expressions.SetCollapsed(e.Property.Expression.Expr);
// just remove edge from underlying object graph (no need to fully rebuild)
e.Property.ObjectGraphProperty.TargetNode = null;

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraphWindow.xaml.cs

@ -42,7 +42,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -42,7 +42,7 @@ namespace Debugger.AddIn.Visualizers.Graph
ObjectGraphWindow.Instance = null; // allow release
}
public ICSharpCode.NRefactory.Ast.Expression ShownExpression
public GraphExpression ShownExpression
{
get { return this.objectGraphControl.ShownExpression; }
set { this.objectGraphControl.ShownExpression = value; }

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml

@ -27,9 +27,6 @@ @@ -27,9 +27,6 @@
<Border Margin="3" Padding="3">
<DockPanel>
<TextBlock VerticalAlignment="Center">Expression:</TextBlock>
<TextBox Name="txtExpression" VerticalAlignment="Center" Width="100"></TextBox>
<Button Name="btnInspect" Click="btnInspect_Click">Inspect</Button>
<ComboBox Name="cmbColumns" Style="{StaticResource styleColumnsComboBox}" Width="74" Height="20" HorizontalAlignment="Right">
<ComboBox.ItemTemplate>
<DataTemplate>

198
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs

@ -2,25 +2,15 @@ @@ -2,25 +2,15 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using Debugger.AddIn.TreeModel;
using Debugger.AddIn.Visualizers.PresentationBindings;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.GridVisualizer
@ -30,160 +20,94 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -30,160 +20,94 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
/// </summary>
public partial class GridVisualizerWindow : Window
{
WindowsDebugger debuggerService;
GridViewColumnHider columnHider;
Func<Value> getValue;
public GridVisualizerWindow()
public GridVisualizerWindow(string valueName, Func<Value> getValue)
{
InitializeComponent();
this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
this.Title = valueName;
this.getValue = getValue;
instance = this;
this.Deactivated += GridVisualizerWindow_Deactivated;
}
void GridVisualizerWindow_Deactivated(object sender, EventArgs e)
{
this.Close();
}
private ICSharpCode.NRefactory.Ast.Expression shownExpression;
public ICSharpCode.NRefactory.Ast.Expression ShownExpression
{
get {
return shownExpression;
}
set {
if (value == null) {
shownExpression = null;
txtExpression.Text = null;
Refresh();
return;
}
if (shownExpression == null || value.PrettyPrint() != shownExpression.PrettyPrint()) {
txtExpression.Text = value.PrettyPrint();
Refresh();
}
}
}
static GridVisualizerWindow instance;
/// <summary> When Window is visible, returns reference to the Window. Otherwise returns null. </summary>
public static GridVisualizerWindow Instance
{
get { return instance; }
}
public static GridVisualizerWindow EnsureShown()
{
var window = GridVisualizerWindow.Instance ?? new GridVisualizerWindow();
window.Topmost = true;
window.Show();
return window;
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
this.Deactivated -= GridVisualizerWindow_Deactivated;
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
instance = null;
}
private void btnInspect_Click(object sender, RoutedEventArgs e)
{
Refresh();
}
public void Refresh()
{
try {
try {
// clear ListView
listView.ItemsSource = null;
ScrollViewer listViewScroller = listView.GetScrollViewer();
if (listViewScroller != null) {
listViewScroller.ScrollToVerticalOffset(0);
}
Value shownValue = null;
ICSharpCode.NRefactory.Ast.Expression shownExpr = null;
try {
shownExpr = debuggerService.GetExpression(txtExpression.Text);
shownValue = shownExpr.Evaluate(debuggerService.DebuggedProcess);
} catch(GetValueException e) {
MessageService.ShowMessage(e.Message);
}
if (shownValue != null && !shownValue.IsNull) {
GridValuesProvider gridValuesProvider;
// Value is IList
DebugType iListType, listItemType;
if (shownValue.Type.ResolveIListImplementation(out iListType, out listItemType)) {
gridValuesProvider = CreateListValuesProvider(shownExpr.CastToIList(), listItemType);
Value shownValue = getValue();
DebugType iListType, iEnumerableType, itemType;
// Value is IList
if (shownValue.Type.ResolveIListImplementation(out iListType, out itemType)) {
// Ok
} else {
// Value is IEnumerable
if (shownValue.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
shownValue = DebuggerHelpers.CreateListFromIEnumerable(shownValue);
iListType = DebugType.CreateFromType(shownValue.AppDomain, typeof(System.Collections.Generic.IList<>), itemType);
} else {
// Value is IEnumerable
DebugType iEnumerableType, itemType;
if (shownValue.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
DebugType debugListType;
var debugListExpression = DebuggerHelpers.CreateDebugListExpression(shownExpr, itemType, out debugListType);
gridValuesProvider = CreateListValuesProvider(debugListExpression, itemType);
} else {
// Not IList or IEnumerable<T> - can't be displayed in GridVisualizer
return;
}
// Not IList or IEnumerable<T> - can't be displayed in GridVisualizer
return;
}
IList<MemberInfo> itemTypeMembers = gridValuesProvider.GetItemTypeMembers();
InitializeColumns((GridView)this.listView.View, itemTypeMembers);
this.columnHider = new GridViewColumnHider((GridView)this.listView.View);
cmbColumns.ItemsSource = this.columnHider.HideableColumns;
}
} catch (GetValueException e) {
MessageService.ShowMessage(e.Message);
} catch (DebuggerVisualizerException e) {
shownValue = shownValue.GetPermanentReference(WindowsDebugger.EvalThread);
MemberInfo[] members = itemType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo itemGetter = iListType.GetProperty("Item");
int rowCount = (int)shownValue.GetPropertyValue(WindowsDebugger.EvalThread, iListType.GetProperty("Count")).PrimitiveValue;
int columnCount = members.Length + 1;
var rowCollection = new VirtualizingCollection<VirtualizingCollection<string>>(
rowCount,
(rowIndex) => new VirtualizingCollection<string>(
columnCount,
(columnIndex) => {
if (columnIndex == members.Length)
return "[" + rowIndex + "]";
try {
var rowValue = shownValue.GetPropertyValue(WindowsDebugger.EvalThread, itemGetter, Eval.CreateValue(WindowsDebugger.EvalThread, rowIndex));
return rowValue.GetMemberValue(WindowsDebugger.EvalThread, members[columnIndex]).InvokeToString(WindowsDebugger.EvalThread);
} catch (GetValueException e) {
return "Exception: " + e.Message;
}
}
)
);
this.listView.ItemsSource = rowCollection;
InitializeColumns((GridView)this.listView.View, members);
GridViewColumnHider columnHider = new GridViewColumnHider((GridView)this.listView.View);
cmbColumns.ItemsSource = columnHider.HideableColumns;
} catch(GetValueException e) {
MessageService.ShowMessage(e.Message);
}
}
ListValuesProvider CreateListValuesProvider(ICSharpCode.NRefactory.Ast.Expression targetExpression, DebugType listItemType)
{
var listValuesProvider = new ListValuesProvider(targetExpression, listItemType);
var virtCollection = new VirtualizingCollection<ObjectValue>(listValuesProvider);
this.listView.ItemsSource = virtCollection;
return listValuesProvider;
}
void InitializeColumns(GridView gridView, IList<MemberInfo> itemTypeMembers)
void InitializeColumns(GridView gridView, MemberInfo[] members)
{
gridView.Columns.Clear();
AddIndexColumn(gridView);
AddMembersColumns(gridView, itemTypeMembers);
}
void AddIndexColumn(GridView gridView)
{
// Index column
var indexColumn = new GridViewHideableColumn();
indexColumn.CanBeHidden = false;
indexColumn.Width = 36;
indexColumn.Header = string.Empty;
indexColumn.DisplayMemberBinding = new Binding("Index");
indexColumn.DisplayMemberBinding = new Binding("[" + members.Length + "]");
gridView.Columns.Add(indexColumn);
}
void AddMembersColumns(GridView gridView, IList<MemberInfo> itemTypeMembers)
{
foreach (var member in itemTypeMembers) {
// Member columns
for (int i = 0; i < members.Length; i++) {
var memberColumn = new GridViewHideableColumn();
memberColumn.CanBeHidden = true;
memberColumn.Header = member.Name;
// "{Binding Path=[Name].Value}"
memberColumn.DisplayMemberBinding = new Binding("[" + member.Name + "].Value");
memberColumn.Header = members[i].Name;
memberColumn.IsVisibleDefault = ((IDebugMemberInfo)members[i]).IsPublic;
memberColumn.DisplayMemberBinding = new Binding("[" + i + "]");
gridView.Columns.Add(memberColumn);
}
}

85
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Services;
using System.Reflection;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Item of a collection in the debugee, with lazy evaluated properties.
/// </summary>
public class ObjectValue
{
/// <summary> Index of this item in the collection. </summary>
public int Index { get; private set; }
// PermanentReference for one row.
public Value PermanentReference { get; private set; }
private Dictionary<string, ObjectProperty> properties = new Dictionary<string, ObjectProperty>();
/// <summary> Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members </summary>
private Dictionary<string, MemberInfo> memberForNameMap;
internal ObjectValue(int index, Dictionary<string, MemberInfo> memberFromNameMap)
{
this.Index = index;
this.memberForNameMap = memberFromNameMap;
}
/// <summary>
/// Returns property with given name.
/// </summary>
public ObjectProperty this[string propertyName]
{
get
{
ObjectProperty property;
// has property with name 'propertyName' already been evaluated?
if(!this.properties.TryGetValue(propertyName, out property))
{
if (this.PermanentReference == null) {
throw new DebuggerVisualizerException("Cannot get member of this ObjectValue - ObjectValue.PermanentReference is null");
}
MemberInfo memberInfo = this.memberForNameMap.GetValue(propertyName);
if (memberInfo == null) {
throw new DebuggerVisualizerException("Cannot get member value - no member found with name " + propertyName);
}
property = CreatePropertyFromValue(propertyName, this.PermanentReference.GetMemberValue(memberInfo));
this.properties.Add(propertyName, property);
}
return property;
}
}
public static ObjectValue Create(Debugger.Value value, int index, Dictionary<string, MemberInfo> memberFromName)
{
ObjectValue result = new ObjectValue(index, memberFromName);
// remember PermanentReference for expanding IEnumerable
Value permanentReference = value.GetPermanentReference();
result.PermanentReference = permanentReference;
return result;
}
private static ObjectProperty CreatePropertyFromValue(string propertyName, Value value)
{
ObjectProperty property = new ObjectProperty();
property.Name = propertyName;
// property.Expression = ?.Age
// - cannot use expression,
// if the value is returned from an enumerator, it has no meaningful expression
property.IsAtomic = value.Type.IsPrimitive;
property.IsNull = value.IsNull;
property.Value = value.IsNull ? "" : value.InvokeToString();
return property;
}
}
}

50
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs

@ -1,50 +0,0 @@ @@ -1,50 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Services;
using System.Reflection;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IEnumerable.
/// </summary>
/*public class EnumerableValuesProvider : GridValuesProvider
{
public EnumerableValuesProvider(Expression targetObject, DebugType iEnumerableType, DebugType itemType)
:base(targetObject, iEnumerableType, itemType)
{
this.itemsSource = enumerateItems();
}
private IEnumerable<ObjectValue> itemsSource;
public IEnumerable<ObjectValue> ItemsSource
{
get { return this.itemsSource; }
}
private IEnumerable<ObjectValue> enumerateItems()
{
MethodInfo enumeratorMethod = collectionType.GetMethod("GetEnumerator");
Value enumerator = targetObject.Evaluate(WindowsDebugger.CurrentProcess).InvokeMethod(enumeratorMethod, null).GetPermanentReference();
MethodInfo moveNextMethod = enumerator.Type.GetMethod("MoveNext");
PropertyInfo currentproperty = enumerator.Type.GetInterface(typeof(IEnumerator).FullName).GetProperty("Current");
int index = 0;
while ((bool)enumerator.InvokeMethod(moveNextMethod, null).PrimitiveValue)
{
Value currentValue = enumerator.GetPropertyValue(currentproperty);
yield return ObjectValue.Create(currentValue, index++, this.memberFromNameMap);
}
}
}*/
}

42
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using System.Reflection;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s to be displayed in Grid visualizer.
/// Descandants implement getting values for IList and IEnumerable.
/// </summary>
public class GridValuesProvider
{
/// <summary> Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members </summary>
protected Dictionary<string, MemberInfo> memberFromNameMap;
protected Expression targetObject;
protected DebugType itemType;
public GridValuesProvider(Expression targetObject, DebugType itemType)
{
this.targetObject = targetObject;
this.itemType = itemType;
this.memberFromNameMap = this.GetItemTypeMembers().MakeDictionary(memberInfo => memberInfo.Name);
}
/// <summary>
/// Gets members that will be displayed as columns.
/// </summary>
public IList<MemberInfo> GetItemTypeMembers()
{
var publicPropetiesAndFields = itemType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance);
return publicPropetiesAndFields;
}
}
}

59
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs

@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IList.
/// </summary>
public class ListValuesProvider : GridValuesProvider, IListValuesProvider<ObjectValue>
{
int? listCount = null;
/// <summary>
/// After evaluating how many items to clear debugger Expression cache,
/// so that the cache does not keep too many PermanentReferences.
/// </summary>
static readonly int ClearCacheThreshold = 50;
public ListValuesProvider(Expression targetObject, DebugType listItemType)
:base(targetObject, listItemType)
{
}
public int GetCount()
{
if (this.listCount == null) {
this.listCount = this.targetObject.GetIListCount();
}
return this.listCount.Value;
}
/// <summary>When this reaches ClearCacheThreshold, the debugger Expression cache is cleared.</summary>
int itemClearCacheCounter = 0;
public ObjectValue GetItemAt(int index)
{
if (itemClearCacheCounter++ > ClearCacheThreshold) {
// clear debugger Expression cache to avoid holding too many PermanentReferences
WindowsDebugger.CurrentProcess.ClearExpressionCache();
LoggingService.Info("Cleared debugger Expression cache.");
itemClearCacheCounter = 0;
}
return ObjectValue.Create(
targetObject.AppendIndexer(index).Evaluate(WindowsDebugger.CurrentProcess),
//targetObject.AppendIndexer(index), // use Expression instead of value - possible only for IList though
index,
this.memberFromNameMap);
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System.Collections.Generic;
using System.Linq;
using System;
public enum TextVisualizerMode
{
PlainText,
Xml
}

48
src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs

@ -1,17 +1,9 @@ @@ -1,17 +1,9 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using ICSharpCode.AvalonEdit.Highlighting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
namespace Debugger.AddIn.Visualizers.TextVisualizer
{
@ -20,42 +12,14 @@ namespace Debugger.AddIn.Visualizers.TextVisualizer @@ -20,42 +12,14 @@ namespace Debugger.AddIn.Visualizers.TextVisualizer
/// </summary>
public partial class TextVisualizerWindow : Window
{
public TextVisualizerWindow()
{
InitializeComponent();
Mode = TextVisualizerMode.PlainText;
textEditor.IsReadOnly = true;
}
public TextVisualizerWindow(string title, string text)
public TextVisualizerWindow(string title, string text, string highlighting = null)
{
InitializeComponent();
Title= title;
Text = text;
}
public string Text
{
get { return this.textEditor.Text; }
set { this.textEditor.Text = value; }
}
private TextVisualizerMode mode;
public TextVisualizerMode Mode
{
get { return mode; }
set {
mode = value;
switch (mode) {
case TextVisualizerMode.PlainText:
textEditor.SyntaxHighlighting = null;
break;
case TextVisualizerMode.Xml:
textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
break;
}
}
Title = title;
this.textEditor.Text = text;
if (highlighting != null)
this.textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(highlighting);
}
void CheckBox_CheckedChanged(object sender, RoutedEventArgs e)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save