11 changed files with 1297 additions and 0 deletions
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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> |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue