Browse Source

C# Outline Pad

A c# outline pad, based on the syntax tree
pull/520/head
JohnnyBravo75 11 years ago
parent
commit
ccf71cc67e
  1. 11
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
  2. 9
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  3. 29
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs
  4. 524
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs
  5. 128
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs
  6. 13
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml
  7. 352
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs
  8. 169
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs
  9. 51
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs
  10. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
  11. 8
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs

11
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin

@ -33,6 +33,17 @@
</Condition> </Condition>
</Path> </Path>
<Path name = "/SharpDevelop/Pads/OutlinePad/ContextMenu/NodeActions">
<MenuItem id = "RemoveNode"
label = "Remove"
icon = "Icons.16x16.DeleteIcon"
class = "CSharpBinding.OutlinePad.RemoveNodeCommand"/>
<MenuItem id = "SelectRegion"
label = "Mark text"
icon = ""
class = "CSharpBinding.OutlinePad.SelectRegionCommand"/>
</Path>
<Path name = "/SharpDevelop/MSBuildEngine/CompileTaskNames"> <Path name = "/SharpDevelop/MSBuildEngine/CompileTaskNames">
<!-- Makes SharpDevelop show the text 'Compiling ProjectName...' when the task is started --> <!-- Makes SharpDevelop show the text 'Compiling ProjectName...' when the task is started -->
<String id="csc" text = "csc"/> <String id="csc" text = "csc"/>

9
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -115,6 +115,13 @@
<DependentUpon>CSharpProjectFormattingOptions.xaml</DependentUpon> <DependentUpon>CSharpProjectFormattingOptions.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Src\OutlinePad\AstNodeHelper.cs" />
<Compile Include="Src\OutlinePad\CSharpOutlineCommands.cs" />
<Compile Include="Src\OutlinePad\CSharpOutlineContentHost.xaml.cs">
<DependentUpon>CSharpOutlineContentHost.xaml</DependentUpon>
</Compile>
<Compile Include="Src\OutlinePad\CSharpOutlineNode.cs" />
<Compile Include="Src\OutlinePad\ExtensionMethods.cs" />
<Compile Include="Src\Parser\FoldingVisitor.cs" /> <Compile Include="Src\Parser\FoldingVisitor.cs" />
<Compile Include="Src\Refactoring\AbstractInlineRefactorDialog.cs" /> <Compile Include="Src\Refactoring\AbstractInlineRefactorDialog.cs" />
<Compile Include="Src\Refactoring\ConvertInterfaceToAbstractClassContextAction.cs" /> <Compile Include="Src\Refactoring\ConvertInterfaceToAbstractClassContextAction.cs" />
@ -264,6 +271,7 @@
<Page Include="Src\OptionPanels\CSharpFormattingEditor.xaml" /> <Page Include="Src\OptionPanels\CSharpFormattingEditor.xaml" />
<Page Include="Src\OptionPanels\CSharpFormattingOptionPanel.xaml" /> <Page Include="Src\OptionPanels\CSharpFormattingOptionPanel.xaml" />
<Page Include="Src\OptionPanels\CSharpProjectFormattingOptions.xaml" /> <Page Include="Src\OptionPanels\CSharpProjectFormattingOptions.xaml" />
<Page Include="Src\OutlinePad\CSharpOutlineContentHost.xaml" />
<Page Include="Src\Refactoring\CreatePropertiesDialog.xaml" /> <Page Include="Src\Refactoring\CreatePropertiesDialog.xaml" />
<Page Include="Src\Refactoring\InsertCtorDialog.xaml" /> <Page Include="Src\Refactoring\InsertCtorDialog.xaml" />
<Page Include="Src\Refactoring\IssueOptions.xaml" /> <Page Include="Src\Refactoring\IssueOptions.xaml" />
@ -274,6 +282,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Src\FormsDesigner" /> <Folder Include="Src\FormsDesigner" />
<Folder Include="Src\OutlinePad" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

29
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs

@ -24,10 +24,14 @@ using System.Reflection;
using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit;
using CSharpBinding.FormattingStrategy; using CSharpBinding.FormattingStrategy;
using CSharpBinding.Refactoring; using CSharpBinding.Refactoring;
using CSharpBinding.OutlinePad;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Refactoring; using ICSharpCode.SharpDevelop.Refactoring;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.AvalonEdit.Rendering;
namespace CSharpBinding namespace CSharpBinding
{ {
public class CSharpTextEditorExtension : ITextEditorExtension public class CSharpTextEditorExtension : ITextEditorExtension
@ -46,6 +50,8 @@ namespace CSharpBinding
TextEditorOptions originalEditorOptions; TextEditorOptions originalEditorOptions;
CSharpOutlineContentHost contentHost;
public void Attach(ITextEditor editor) public void Attach(ITextEditor editor)
{ {
this.editor = editor; this.editor = editor;
@ -75,6 +81,17 @@ namespace CSharpBinding
// Set TextEditor's options to same object // Set TextEditor's options to same object
originalEditorOptions = textEditor.Options; originalEditorOptions = textEditor.Options;
textEditor.Options = options.TextEditorOptions; textEditor.Options = options.TextEditorOptions;
// add the outline pad
var textView = textEditor.TextArea.TextView;
if (textView != null) {
if (SD.Workbench != null) {
// add the CSharpOutlineContentHost, which manages the tree view
contentHost = new CSharpOutlineContentHost(editor);
textView.Services.AddService(typeof(IOutlineContentHost), contentHost);
}
textView.Services.AddService(typeof(CSharpTextEditorExtension), this);
}
} }
} }
@ -83,13 +100,25 @@ namespace CSharpBinding
var textEditor = editor.GetService<TextEditor>(); var textEditor = editor.GetService<TextEditor>();
if (textEditor != null) { if (textEditor != null) {
var textView = textEditor.TextArea.TextView; var textView = textEditor.TextArea.TextView;
// Unregister our ITextEditorOptions instance from editor // Unregister our ITextEditorOptions instance from editor
var optionsService = textView.GetService<ITextEditorOptions>(); var optionsService = textView.GetService<ITextEditorOptions>();
if ((optionsService != null) && (optionsService == options)) if ((optionsService != null) && (optionsService == options))
textView.Services.RemoveService(typeof(ITextEditorOptions)); textView.Services.RemoveService(typeof(ITextEditorOptions));
// Reset TextEditor options, too? // Reset TextEditor options, too?
if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions)) if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions))
textEditor.Options = originalEditorOptions; textEditor.Options = originalEditorOptions;
// remove the outline pad
if (textView != null) {
if (contentHost != null) {
textView.Services.RemoveService(typeof(IOutlineContentHost));
contentHost.Dispose();
contentHost = null;
}
textView.Services.RemoveService(typeof(CSharpTextEditorExtension));
}
} }
codeManipulation.Dispose(); codeManipulation.Dispose();

524
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs

@ -0,0 +1,524 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace CSharpBinding.OutlinePad
{
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Text;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.AvalonEdit.Highlighting;
internal static class AstNodeHelper {
static bool showExtendedInfos = true;
static bool colorizeNode = false;
static HighlightingColor nameSpaceHighLighting, regionHighLighting, classHighLighting, methodHighLighting, interfaceHighLighting;
static AstNodeHelper() {
var highlightingDefinition = HighlightingManager.Instance.GetDefinition("C#");
nameSpaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "NamespaceKeywords");
regionHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "Preprocessor");
classHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords");
interfaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords");
methodHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "MethodCall");
}
private static Modifiers GetAccessModifier(AstNode node) {
var accessModifier = node.Children.FirstOrDefault(x => x is CSharpModifierToken &&
((x as CSharpModifierToken).Modifier == Modifiers.Public ||
(x as CSharpModifierToken).Modifier == Modifiers.Protected ||
(x as CSharpModifierToken).Modifier == Modifiers.Private ||
(x as CSharpModifierToken).Modifier == Modifiers.Internal )) as CSharpModifierToken;
// special case: All members in an interface are public, although they have no access modifier
if (accessModifier == null && IsInterface(node.Parent)) {
return Modifiers.Public;
}
return accessModifier == null ? Modifiers.None : accessModifier.Modifier;
}
private static string GetParameterDeclsAsString(AstNodeCollection<ParameterDeclaration> parameterDecls) {
var parameterString = new StringBuilder();
int current = 0;
foreach (var paramDecl in parameterDecls) {
if (paramDecl.ParameterModifier != ParameterModifier.None) {
parameterString.Append(paramDecl.ParameterModifier.ToString().ToLower());
parameterString.Append(" ");
}
parameterString.Append(paramDecl.Type.ToString());
parameterString.Append(" ");
parameterString.Append(paramDecl.Name);
if (current < (parameterDecls.Count - 1)) {
parameterString.Append(", ");
}
current++;
}
return parameterString.ToString();
}
private static string GetTypeParameterDeclsAsString(AstNodeCollection<TypeParameterDeclaration> parameterDecls) {
var parameterString = new StringBuilder();
int current = 0;
foreach (var paramDecl in parameterDecls) {
parameterString.Append(paramDecl.NameToken.ToString());
if (current < (parameterDecls.Count - 1)) {
parameterString.Append(", ");
}
current++;
}
return parameterString.ToString();
}
public static bool IsAllowedNode(AstNode node) {
return (IsRegionStart(node)
|| IsRegionEnd(node)
|| IsClass(node)
|| IsInterface(node)
|| IsMethod(node)
|| IsField(node)
|| IsProperty(node)
|| IsNameSpace(node)
|| IsConstructor(node)
|| IsEvent(node)
|| IsDelegate(node)
|| IsIndexer(node)
|| IsEnum(node)
|| IsEnumMember(node)
|| IsStruct(node)
|| IsOperator(node)
);
}
public static bool IsRegionStart(AstNode node) {
return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Region);
}
internal static void SetRegionStartInfos(CSharpOutlineNode node, AstNode dataNode) {
var preProcessorNode = (PreProcessorDirective)dataNode;
node.ElementName = "****** " + preProcessorNode.Argument + " *****";
node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal;
}
public static bool IsRegionEnd(AstNode node) {
return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Endregion);
}
internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) {
var preProcessorNode = (PreProcessorDirective)dataNode;
node.ElementName = "*********************";
node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal;
}
public static bool IsDelegate(AstNode node) {
return (node is DelegateDeclaration);
}
internal static void SetDelegateNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var typeNode = (DelegateDeclaration)dataNode;
node.ElementName = typeNode.Name;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Delegate";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedDelegate";
break;
case Modifiers.Private:
node.IconName = "Icons.16x16.PrivateDelegate";
break;
default:
node.IconName = "Icons.16x16.InternalDelegate";
break;
}
}
public static bool IsStruct(AstNode node) {
return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Struct);
}
internal static void SetStructNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var typeNode = (TypeDeclaration)dataNode;
node.ElementName = typeNode.Name;
if (colorizeNode)
node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
node.IsExpanded = true;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Struct";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedStruct";
break;
case Modifiers.Private:
node.IconName = "Icons.16x16.PrivateStruct";
break;
default:
node.IconName = "Icons.16x16.InternalStruct";
break;
}
}
public static bool IsEnumMember(AstNode node) {
return (node is EnumMemberDeclaration);
}
internal static void SetEnumMemberNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var enumMemberNode = (EnumMemberDeclaration)dataNode;
node.ElementName = enumMemberNode.Name;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
node.IconName = "Icons.16x16.Enum";
}
public static bool IsEnum(AstNode node) {
return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Enum);
}
internal static void SetEnumNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var typeNode = (TypeDeclaration)dataNode;
node.ElementName = typeNode.Name;
if (colorizeNode)
node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
node.IsExpanded = true;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Enum";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedEnum";
break;
case Modifiers.Private:
node.IconName = "Icons.16x16.PrivateEnum";
break;
default:
node.IconName = "Icons.16x16.InternalEnum";
break;
}
}
public static bool IsClass(AstNode node) {
return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Class);
}
internal static void SetClassNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var typeNode = (TypeDeclaration)dataNode;
node.ElementName = typeNode.Name
+ typeNode.LChevronToken
+ GetTypeParameterDeclsAsString(typeNode.TypeParameters)
+ typeNode.RChevronToken;
if (colorizeNode)
node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
node.IsExpanded = true;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Class";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedClass";
break;
case Modifiers.Private:
node.IconName = "Icons.16x16.PrivateClass";
break;
default:
node.IconName = "Icons.16x16.InternalClass";
break;
}
}
public static bool IsEvent(AstNode node) {
return (node is EventDeclaration);
}
internal static void SetEventNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var eventNode = (EventDeclaration)dataNode;
var varInitializer = eventNode.Children.FirstOrDefault(x => x is VariableInitializer) as VariableInitializer;
node.ElementName = (varInitializer != null)
? varInitializer.Name
: "<unknown>";
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Event";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedEvent";
break;
default:
node.IconName = "Icons.16x16.PrivateEvent";
break;
}
}
public static bool IsInterface(AstNode node) {
return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Interface);
}
internal static void SetInterfaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var typeNode = (TypeDeclaration)dataNode;
node.ElementName = typeNode.Name;
if (colorizeNode)
node.ForegroundBrush = (interfaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
node.IsExpanded = true;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Interface";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedInterface";
break;
case Modifiers.Private:
node.IconName = "Icons.16x16.PrivateInterface";
break;
default:
node.IconName = "Icons.16x16.InternalInterface";
break;
}
}
public static bool IsOperator(AstNode node) {
return (node is OperatorDeclaration);
}
internal static void SetOperatorNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var operatorNode = (OperatorDeclaration)dataNode;
node.ElementName = operatorNode.OperatorToken
+ " " + operatorNode.OperatorTypeToken;
if (showExtendedInfos) {
node.ElementName += " " + operatorNode.LParToken
+ GetParameterDeclsAsString(operatorNode.Parameters)
+ operatorNode.RParToken;
}
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Method";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedMethod";
break;
default:
node.IconName = "Icons.16x16.PrivateMethod";
break;
}
}
public static bool IsMethod(AstNode node) {
return (node is MethodDeclaration);
}
internal static void SetMethodNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var methodNode = (MethodDeclaration)dataNode;
node.ElementName = methodNode.Name;
node.ElementName += " " + methodNode.LParToken
+ (showExtendedInfos ? GetParameterDeclsAsString(methodNode.Parameters) : "")
+ methodNode.RParToken;
if (colorizeNode)
node.ForegroundBrush = (methodHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = methodHighLighting.FontWeight != null ? methodHighLighting.FontWeight.Value : FontWeights.Normal;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Method";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedMethod";
break;
default:
node.IconName = "Icons.16x16.PrivateMethod";
break;
}
}
public static bool IsField(AstNode node) {
return (node is FieldDeclaration);
}
internal static void SetFieldNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var fieldNode = (FieldDeclaration)dataNode;
var fieldName = new StringBuilder();
int current = 0;
foreach (var varInitializer in fieldNode.Variables) {
fieldName.Append(varInitializer.Name);
if (current < (fieldNode.Variables.Count - 1)) {
fieldName.Append(", ");
}
current++;
}
node.ElementName = fieldName.ToString();
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Field";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedField";
break;
default:
node.IconName = "Icons.16x16.PrivateField";
break;
}
}
public static bool IsProperty(AstNode node) {
return (node is PropertyDeclaration);
}
internal static void SetPropertyNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var propertyNode = (PropertyDeclaration)dataNode;
node.ElementName = propertyNode.Name;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
if (showExtendedInfos) {
node.ElementName += " " + propertyNode.LBraceToken
+ " " + propertyNode.Getter.Keyword + (!string.IsNullOrEmpty(propertyNode.Getter.Keyword.ToString()) ? ";" : "")
+ " " + propertyNode.Setter.Keyword + (!string.IsNullOrEmpty(propertyNode.Setter.Keyword.ToString()) ? ";" : "")
+ " " + propertyNode.RBraceToken;
}
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Property";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedProperty";
break;
default:
node.IconName = "Icons.16x16.PrivateProperty";
break;
}
}
public static bool IsIndexer(AstNode node) {
return (node is IndexerDeclaration);
}
internal static void SetIndexerNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var indexerNode = (IndexerDeclaration)dataNode;
node.ElementName = indexerNode.ReturnType.ToString() + " " + indexerNode.ThisToken.ToString()
+ indexerNode.LBracketToken
+ GetParameterDeclsAsString(indexerNode.Parameters)
+ indexerNode.RBracketToken;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
if (showExtendedInfos) {
node.ElementName += " " + indexerNode.LBraceToken
+ " " + indexerNode.Getter.Keyword + (!string.IsNullOrEmpty(indexerNode.Getter.Keyword.ToString()) ? ";" : "")
+ " " + indexerNode.Setter.Keyword + (!string.IsNullOrEmpty(indexerNode.Setter.Keyword.ToString()) ? ";" : "")
+ " " + indexerNode.RBraceToken;
}
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Property";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedProperty";
break;
default:
node.IconName = "Icons.16x16.PrivateProperty";
break;
}
}
public static bool IsNameSpace(AstNode node) {
return (node is NamespaceDeclaration);
}
internal static void SetNameSpaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var nameSpaceNode = (NamespaceDeclaration)dataNode;
node.ElementName = nameSpaceNode.Name;
node.IconName = "Icons.16x16.NameSpace";
node.IsExpanded = true;
if (colorizeNode)
node.ForegroundBrush = (nameSpaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
// node.Weight = nameSpaceHighLighting.FontWeight != null ? nameSpaceHighLighting.FontWeight.Value : FontWeights.Normal;
}
public static bool IsConstructor(AstNode node) {
return (node is ConstructorDeclaration);
}
internal static void SetConstructorNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
var constructorNode = (ConstructorDeclaration)dataNode;
node.ElementName = constructorNode.Name;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
node.ElementName += " "
+ constructorNode.LParToken
+ (showExtendedInfos ? GetParameterDeclsAsString(constructorNode.Parameters) : "")
+ constructorNode.RParToken;
switch(GetAccessModifier(dataNode)) {
case Modifiers.Public:
node.IconName = "Icons.16x16.Method";
break;
case Modifiers.Protected:
node.IconName = "Icons.16x16.ProtectedMethod";
break;
default:
node.IconName = "Icons.16x16.PrivateMethod";
break;
}
}
public static bool IsDocument(AstNode node) {
return (node is SyntaxTree);
}
internal static void SetDocumentNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
node.ElementName = Path.GetFileName(((SyntaxTree)dataNode).FileName);
node.IconName = "C#.File.FullFile";
node.IsExpanded = true;
node.Weight = FontWeights.Bold;
if (colorizeNode)
node.ForegroundBrush = Brushes.Black;
}
}
}

128
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs

@ -0,0 +1,128 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace CSharpBinding.OutlinePad
{
using System;
using ICSharpCode.SharpDevelop;
using ICSharpCode.AvalonEdit.Folding;
using System.Linq;
/// <summary>
/// RemoveNodeCommand.
/// </summary>
public class RemoveNodeCommand : SimpleCommand
{
public override bool CanExecute(object parameter) {
var node = parameter as CSharpOutlineNode;
if (node == null)
return false;
if (node.StartMarker == null || node.EndMarker == null)
return false;
if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
return false;
if (node.EndMarker.Offset == 0)
return false;
if (node.EndMarker.Offset < node.StartMarker.Offset)
return false;
return true;
}
public override void Execute(object parameter) {
var node = parameter as CSharpOutlineNode;
node.Editor.Document.Remove(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
}
}
/// <summary>
/// SelectRegionCommand.
/// </summary>
public class SelectRegionCommand : SimpleCommand
{
public override bool CanExecute(object parameter) {
var node = parameter as CSharpOutlineNode;
if (node == null)
return false;
if (node.StartMarker == null || node.EndMarker == null)
return false;
if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
return false;
if (node.EndMarker.Offset == 0)
return false;
if (node.EndMarker.Offset < node.StartMarker.Offset)
return false;
return true;
}
public override void Execute(object parameter) {
var node = parameter as CSharpOutlineNode;
node.Editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
}
}
/// <summary>
/// HandleFoldingCommand
/// </summary>
public class HandleFoldingCommand : SimpleCommand
{
public override bool CanExecute(object parameter) {
var node = parameter as CSharpOutlineNode;
if (node == null)
return false;
if (node.StartMarker == null || node.EndMarker == null)
return false;
if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
return false;
if (node.EndMarker.Offset == 0)
return false;
if (node.EndMarker.Offset < node.StartMarker.Offset)
return false;
return true;
}
public override void Execute(object parameter) {
var node = parameter as CSharpOutlineNode;
if (node == null || node.Editor == null)
return;
FoldingManager foldingManager = node.Editor.GetService(typeof(FoldingManager)) as FoldingManager;
if (foldingManager == null)
return;
// The endline is, where the first child starts. The folding has to be
// between the StartMarker.Line of the current node and the StartMarker.Line of the first child.
int endLine = node.StartMarker.Line;
var firstChild = node.Children.FirstOrDefault();
if (firstChild != null) {
endLine = (firstChild as CSharpOutlineNode).StartMarker.Line;
}
FoldingSection folding = foldingManager.GetNextFolding(node.StartMarker.Offset);
if (folding == null)
return;
// is next folding below the endline, the it belongs to a other node
if (node.Editor.Document.GetLineForOffset(folding.StartOffset).LineNumber >= endLine)
return;
folding.IsFolded = !node.IsExpanded;
}
}
}

13
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml

@ -0,0 +1,13 @@
<DockPanel x:Class="CSharpBinding.OutlinePad.CSharpOutlineContentHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:treeview="http://icsharpcode.net/sharpdevelop/treeview"
>
<treeview:SharpTreeView
x:Name="treeView"
AllowDrop="True"
AllowDropOrder="True"
MouseDoubleClick="TreeViewMouseDoubleClick"
MouseLeftButtonUp="TreeView_MouseLeftButtonUp"
/>
</DockPanel>

352
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs

@ -0,0 +1,352 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Parser;
using CSharpBinding.Parser;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Folding;
namespace CSharpBinding.OutlinePad
{
/// <summary>
/// Interaction logic for CSharpOutlineContentHost.xaml
/// </summary>
public partial class CSharpOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable
{
ITextEditor editor;
DispatcherTimer updateTreeTimer = new DispatcherTimer();
DispatcherTimer scrollToNodeTimer = new DispatcherTimer();
SyntaxTree syntaxTree;
TextLocation? lastCaretLocation;
CSharpOutlineNode selectedNode = null;
static double refreshDelayInMilliSec = 1000;
static bool optionSelectActiveTreeNode = true;
static bool optionSelectRange = false;
public CSharpOutlineContentHost(ITextEditor editor) {
this.editor = editor;
this.editor.Caret.LocationChanged += CaretLocationChanged;
InitializeComponent();
SD.ParserService.ParseInformationUpdated += ParseInfoUpdated;
this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(refreshDelayInMilliSec);
this.updateTreeTimer.Tick += this.UpdateTreeTimer_Tick;
this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(200);
this.scrollToNodeTimer.Tick += this.ScrollToNodeTimer_Tick;
}
void ParseInfoUpdated(object sender, ParseInformationEventArgs e) {
if (this.editor == null || !FileUtility.IsEqualFileName(this.editor.FileName, e.FileName))
return;
var parseInfo = e.NewParseInformation as CSharpFullParseInformation;
if (parseInfo != null && parseInfo.SyntaxTree != null) {
this.updateTreeTimer.Stop();
this.syntaxTree = parseInfo.SyntaxTree;
this.updateTreeTimer.Start();
}
}
void CaretLocationChanged(object sender, EventArgs e)
{
SelectActiveTreeNode();
}
void SelectActiveTreeNode() {
if (!optionSelectActiveTreeNode)
return;
// prevent unnecessary looping, when both CaretLocationChanged and ParseUpdateChanged are fired.
if (this.lastCaretLocation.HasValue && this.lastCaretLocation == this.editor.Caret.Location)
return;
// same line, mostly in the same region, no update needed (there is a small inaccuracy, when entering a method/member)
// if (this.lastCaretLocation.HasValue && this.lastCaretLocation.Value.Line == this.editor.Caret.Location.Line)
// return;
this.lastCaretLocation = this.editor.Caret.Location;
selectedNode = null;
FindNodeFromLocation(this.editor.Caret.Location, treeView.Root as CSharpOutlineNode);
if (selectedNode != null && treeView.SelectedItem != selectedNode) {
treeView.SelectedItem = selectedNode;
if (!scrollToNodeTimer.IsEnabled) {
scrollToNodeTimer.Start();
}
}
}
bool IsRangeInside(TextLocation outerStartLocation, TextLocation outerEndLocation,
TextLocation innerStartLocation, TextLocation innerEndLocation) {
if (outerStartLocation.IsEmpty || outerStartLocation.IsInfinite() ||
outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() ||
innerStartLocation.IsEmpty || innerStartLocation.IsInfinite() ||
innerEndLocation.IsEmpty || innerEndLocation.IsInfinite())
return false;
const int virtualLineLength = 200;
var outerRange = (outerEndLocation.Line - outerStartLocation.Line) * virtualLineLength - outerStartLocation.Column + outerEndLocation.Column;
var innerRange = (innerEndLocation.Line - innerStartLocation.Line) * virtualLineLength - innerStartLocation.Column + innerEndLocation.Column;
return innerRange < outerRange;
}
void FindNodeFromLocation(TextLocation location, CSharpOutlineNode node) {
if (node == null)
return;
if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
return;
if (location.IsInside(node.StartMarker.Location, node.EndMarker.Location)
&& (selectedNode == null || IsRangeInside(selectedNode.AstNodeItem.StartLocation, selectedNode.AstNodeItem.EndLocation,
node.AstNodeItem.StartLocation, node.AstNodeItem.EndLocation))) {
selectedNode = node;
}
foreach(var child in node.Children) {
FindNodeFromLocation(location, child as CSharpOutlineNode);
}
}
void UpdateTreeTimer_Tick(Object sender, EventArgs args) {
this.updateTreeTimer.Stop();
this.UpdateTree(this.syntaxTree);
this.SelectActiveTreeNode();
}
void ScrollToNodeTimer_Tick(Object sender, EventArgs args) {
this.scrollToNodeTimer.Stop();
if (selectedNode != null) {
treeView.ScrollIntoView(selectedNode);
}
}
void UpdateTree(AstNode syntaxTree) {
if (syntaxTree == null)
return;
if (treeView.Root == null) {
treeView.Root = new CSharpOutlineNode();
SetNodeInfos(treeView.Root as CSharpOutlineNode, null, syntaxTree);
}
this.UpdateNode(treeView.Root as CSharpOutlineNode, syntaxTree);
}
void UpdateNode(CSharpOutlineNode node, AstNode dataNode) {
if (dataNode == null || node == null)
return;
SetNodeInfos(node, null, dataNode);
// Filter the children, for only the needed/wanted nodes
var dataChildren = dataNode.Children.Where(childNode => AstNodeHelper.IsAllowedNode(childNode)).ToList();
int childrenCount = node.Children.Count;
int dataCount = dataChildren.Count;
for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) {
if (i >= childrenCount) {
// if (AstNodeHelper.IsRegionStart(dataChildren[i])) {
// var regionNode = new CSharpOutlineNode();
// SetNodeInfos(regionNode, node, dataChildren[i]);
// node.Children.Add(regionNode);
// node = regionNode;
// continue;
// }
// if (AstNodeHelper.IsRegionEnd(dataChildren[i])) {
// node = node.Parent;
// continue;
// }
node.Children.Add(BuildNode(node, dataChildren[i]));
} else if (i >= dataCount) {
while (node.Children.Count > dataCount)
node.Children.RemoveAt(dataCount);
} else {
UpdateNode(node.Children[i] as CSharpOutlineNode, dataChildren[i]);
}
}
}
CSharpOutlineNode BuildNode(CSharpOutlineNode parentNode, AstNode dataNode) {
var node = new CSharpOutlineNode();
SetNodeInfos(node, parentNode, dataNode);
// Filter the children, for only the needed/wanted nodes
var dataChildren = dataNode.Children.Where(v => AstNodeHelper.IsAllowedNode(v)).ToList();
foreach (var child in dataChildren) {
// if (AstNodeHelper.IsRegionStart(child)) {
// var regionNode = new CSharpOutlineNode();
// SetNodeInfos(regionNode, node, child);
// node.Children.Add(regionNode);
// node = regionNode;
// continue;
// }
// if (AstNodeHelper.IsRegionEnd(child)) {
// node = node.Parent;
// continue;
// }
node.Children.Add(BuildNode(node, child));
}
return node;
}
void SetNodeInfos(CSharpOutlineNode node, CSharpOutlineNode parentNode, AstNode dataNode) {
int startOffset = 0;
int textLength = Math.Max(editor.Document.TextLength - 1,0);
if (!dataNode.StartLocation.IsValid() || dataNode.StartLocation.Line > editor.Document.LineCount)
startOffset = 0;
else
startOffset = editor.Document.GetOffset(dataNode.StartLocation);
int endOffset = 0;
if (!dataNode.EndLocation.IsValid() || dataNode.EndLocation.Line > editor.Document.LineCount)
endOffset = textLength;
else
endOffset = editor.Document.GetOffset(dataNode.EndLocation);
node.AstNodeItem = dataNode;
node.StartMarker = editor.Document.CreateAnchor(MinMax(startOffset, 0, textLength));
node.EndMarker = editor.Document.CreateAnchor(MinMax(endOffset, 0, textLength));
node.Editor = editor;
node.Parent = parentNode;
if (AstNodeHelper.IsDocument(dataNode))
AstNodeHelper.SetDocumentNodeInfos(node, dataNode);
if (AstNodeHelper.IsNameSpace(dataNode))
AstNodeHelper.SetNameSpaceNodeInfos(node, dataNode);
if (AstNodeHelper.IsRegionStart(dataNode))
AstNodeHelper.SetRegionStartInfos(node, dataNode);
if (AstNodeHelper.IsRegionEnd(dataNode))
AstNodeHelper.SetRegionEndInfos(node, dataNode);
if (AstNodeHelper.IsClass(dataNode))
AstNodeHelper.SetClassNodeInfos(node, dataNode);
if (AstNodeHelper.IsInterface(dataNode))
AstNodeHelper.SetInterfaceNodeInfos(node, dataNode);
if (AstNodeHelper.IsConstructor(dataNode))
AstNodeHelper.SetConstructorNodeInfos(node, dataNode);
if (AstNodeHelper.IsField(dataNode))
AstNodeHelper.SetFieldNodeInfos(node, dataNode);
if (AstNodeHelper.IsProperty(dataNode))
AstNodeHelper.SetPropertyNodeInfos(node, dataNode);
if (AstNodeHelper.IsMethod(dataNode))
AstNodeHelper.SetMethodNodeInfos(node, dataNode);
if (AstNodeHelper.IsEvent(dataNode))
AstNodeHelper.SetEventNodeInfos(node, dataNode);
if (AstNodeHelper.IsDelegate(dataNode))
AstNodeHelper.SetDelegateNodeInfos(node, dataNode);
if (AstNodeHelper.IsIndexer(dataNode))
AstNodeHelper.SetIndexerNodeInfos(node, dataNode);
if (AstNodeHelper.IsEnum(dataNode))
AstNodeHelper.SetEnumNodeInfos(node, dataNode);
if (AstNodeHelper.IsEnumMember(dataNode))
AstNodeHelper.SetEnumMemberNodeInfos(node, dataNode);
if (AstNodeHelper.IsStruct(dataNode))
AstNodeHelper.SetStructNodeInfos(node, dataNode);
if (AstNodeHelper.IsOperator(dataNode))
AstNodeHelper.SetOperatorNodeInfos(node, dataNode);
}
static int MinMax(int value, int lower, int upper) {
return Math.Min(Math.Max(value, lower), upper);
}
void TreeView_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var node = treeView.SelectedItem as CSharpOutlineNode;
if (node == null)
return;
if (optionSelectRange)
editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
FileService.JumpToFilePosition(this.editor.FileName, node.AstNodeItem.StartLocation.Line, node.AstNodeItem.StartLocation.Column);
}
void TreeViewMouseDoubleClick(object sender, MouseButtonEventArgs e) {
}
public object OutlineContent {
get { return this; }
}
public void Dispose() {
SD.ParserService.ParseInformationUpdated -= ParseInfoUpdated;
if (this.editor != null) {
if (this.editor.Caret != null)
this.editor.Caret.LocationChanged -= CaretLocationChanged;
this.editor = null;
}
this.syntaxTree = null;
this.lastCaretLocation = null;
this.selectedNode = null;
if (this.updateTreeTimer != null) {
this.updateTreeTimer.Stop();
this.updateTreeTimer.Tick -= this.UpdateTreeTimer_Tick;
this.updateTreeTimer = null;
}
if (this.scrollToNodeTimer != null) {
this.scrollToNodeTimer.Stop();
this.scrollToNodeTimer.Tick -= this.ScrollToNodeTimer_Tick;
this.scrollToNodeTimer = null;
}
}
}
}

169
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs

@ -0,0 +1,169 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.TreeView;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.Core.Presentation;
using System.Windows.Controls;
using ICSharpCode.AvalonEdit.Folding;
namespace CSharpBinding.OutlinePad
{
class CSharpOutlineNode : SharpTreeNode
{
string elementName, name, iconName;
public string ElementName {
get { return elementName; }
set {
this.elementName = value;
this.RaisePropertyChanged("Text");
}
}
public string Name {
get { return name; }
set {
this.name = value;
this.RaisePropertyChanged("Text");
}
}
public override object ToolTip {
get { return this.GetSourceText(); }
}
public ITextAnchor StartMarker { get; set; }
public ITextAnchor EndMarker { get; set; }
public ITextEditor Editor { get; set; }
public AstNode AstNodeItem { get; set; }
public new CSharpOutlineNode Parent { get; set; }
public string IconName {
get { return iconName; }
set {
iconName = value;
this.RaisePropertyChanged("Icon");
}
}
public string GetSourceText() {
if (StartMarker.IsDeleted || EndMarker.IsDeleted)
return "";
return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset);
}
public override bool CanDelete(SharpTreeNode[] nodes) {
return nodes.OfType<CSharpOutlineNode>().All(n => n.Parent != null);
}
public override void Delete(SharpTreeNode[] nodes) {
DeleteWithoutConfirmation(nodes);
}
public override void DeleteWithoutConfirmation(SharpTreeNode[] nodes) {
foreach (CSharpOutlineNode CSharpNode in nodes.OfType<CSharpOutlineNode>()) {
CSharpNode.DeleteCore();
}
}
void DeleteCore()
{
Editor.Document.Remove(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset);
}
public override object Text {
get { return (!string.IsNullOrEmpty(Name) ? ElementName + " (" + Name + ")" : ElementName); }
}
public override object Icon {
get { return !string.IsNullOrEmpty(this.IconName)
? SD.ResourceService.GetImageSource(this.IconName)
: null; }
}
public override Brush Foreground {
get { return foregroundBrush ?? SystemColors.WindowTextBrush; }
}
Brush foregroundBrush;
public Brush ForegroundBrush {
get {
return foregroundBrush;
}
set {
foregroundBrush = value;
RaisePropertyChanged("Foreground");
}
}
FontWeight weight = FontWeights.Normal;
public FontWeight Weight {
get {
return weight;
}
set {
weight = value;
RaisePropertyChanged("FontWeight");
}
}
FontStyle style = FontStyles.Normal;
public FontStyle Style {
get {
return style;
}
set {
style = value;
RaisePropertyChanged("FontStyle");
}
}
public override FontWeight FontWeight {
get { return Weight; }
}
public override FontStyle FontStyle {
get { return Style; }
}
public override void ShowContextMenu(ContextMenuEventArgs e)
{
MenuService.ShowContextMenu(null, this, "/SharpDevelop/Pads/OutlinePad/ContextMenu/NodeActions");
}
protected override void OnExpanding() {
var cmd = new HandleFoldingCommand();
if (cmd.CanExecute(this))
cmd.Execute(this);
}
protected override void OnCollapsing() {
var cmd = new HandleFoldingCommand();
if (cmd.CanExecute(this))
cmd.Execute(this);
}
}
}

51
src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs

@ -0,0 +1,51 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace CSharpBinding.OutlinePad
{
using System;
using ICSharpCode.NRefactory;
/// <summary>
/// Description of TextLocationExtensions.
/// </summary>
static class TextLocationExtensions {
public static bool IsInfinite(this TextLocation location) {
return location == null || location.Line == int.MaxValue || location.Column == int.MaxValue;
}
public static bool IsValid(this TextLocation location) {
if (location.IsEmpty)
return false;
if (location.IsInfinite())
return false;
return true;
}
public static bool IsInside(this TextLocation location, TextLocation startLocation, TextLocation endLocation) {
if (location.IsEmpty)
return false;
return location.Line >= startLocation.Line &&
(location.Line <= endLocation.Line || endLocation.Line == -1) &&
(location.Line != startLocation.Line || location.Column >= startLocation.Column) &&
(location.Line != endLocation.Line || location.Column <= endLocation.Column);
}
}
}

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs

@ -330,6 +330,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting
// so it will always invalidate the next visual line when a folded line is constructed // so it will always invalidate the next visual line when a folded line is constructed
// and the highlighting stack has changed. // and the highlighting stack has changed.
if (fromLineNumber > textView.Document.LineCount || toLineNumber > textView.Document.LineCount)
return;
if (fromLineNumber == toLineNumber) { if (fromLineNumber == toLineNumber) {
textView.Redraw(textView.Document.GetLineByNumber(fromLineNumber)); textView.Redraw(textView.Document.GetLineByNumber(fromLineNumber));
} else { } else {

8
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs

@ -136,6 +136,14 @@ namespace ICSharpCode.TreeView
get { return Parent != null ? Parent.Level + 1 : 0; } get { return Parent != null ? Parent.Level + 1 : 0; }
} }
public virtual FontWeight FontWeight {
get { return FontWeights.Normal; }
}
public virtual FontStyle FontStyle {
get { return FontStyles.Normal; }
}
public bool IsRoot public bool IsRoot
{ {
get { return Parent == null; } get { return Parent == null; }

Loading…
Cancel
Save