#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

237 lines
8.0 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Editor;
namespace CSharpBinding.Parser
{
// TODO: move this class + NewFolding to NRefactory
class FoldingVisitor : DepthFirstAstVisitor
{
internal List<NewFolding> foldings = new List<NewFolding> ();
internal IDocument document;
int GetOffset(TextLocation location)
{
return document.GetOffset(location);
}
NewFolding AddFolding(TextLocation start, TextLocation end, bool isDefinition = false)
{
if (end.Line <= start.Line)
return null;
NewFolding folding = new NewFolding(GetOffset(start), GetOffset(end));
folding.IsDefinition = isDefinition;
foldings.Add(folding);
return folding;
}
TextLocation GetEndOfPrev(AstNode node)
{
do {
node = node.GetPrevNode();
} while (node.NodeType == NodeType.Whitespace);
return node.EndLocation;
}
#region usings
void AddUsings (AstNode parent)
{
var firstChild = parent.Children.FirstOrDefault (child => child is UsingDeclaration || child is UsingAliasDeclaration);
var node = firstChild;
while (node != null) {
var next = node.GetNextNode ();
if (next is UsingDeclaration || next is UsingAliasDeclaration) {
node = next;
} else {
break;
}
}
if (firstChild != node) {
NewFolding folding = AddFolding(firstChild.StartLocation, node.EndLocation);
if (folding != null) {
folding.Name = "using...";
folding.DefaultClosed = true;
}
}
}
public override void VisitSyntaxTree (SyntaxTree unit)
{
AddUsings (unit);
base.VisitSyntaxTree (unit);
}
public override void VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration)
{
AddUsings (namespaceDeclaration);
if (!namespaceDeclaration.RBraceToken.IsNull)
AddFolding (namespaceDeclaration.LBraceToken.GetPrevNode ().EndLocation, namespaceDeclaration.RBraceToken.EndLocation);
base.VisitNamespaceDeclaration (namespaceDeclaration);
}
#endregion
#region Entity Declarations
public override void VisitTypeDeclaration (TypeDeclaration typeDeclaration)
{
if (!typeDeclaration.RBraceToken.IsNull)
AddFolding (GetEndOfPrev(typeDeclaration.LBraceToken), typeDeclaration.RBraceToken.EndLocation);
base.VisitTypeDeclaration (typeDeclaration);
}
public override void VisitMethodDeclaration (MethodDeclaration methodDeclaration)
{
if (!methodDeclaration.Body.IsNull) {
AddFolding (GetEndOfPrev(methodDeclaration.Body.LBraceToken),
methodDeclaration.Body.RBraceToken.EndLocation, true);
}
base.VisitMethodDeclaration (methodDeclaration);
}
public override void VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration)
{
if (!constructorDeclaration.Body.IsNull)
AddFolding (GetEndOfPrev(constructorDeclaration.Body.LBraceToken),
constructorDeclaration.Body.RBraceToken.EndLocation, true);
base.VisitConstructorDeclaration (constructorDeclaration);
}
public override void VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration)
{
if (!destructorDeclaration.Body.IsNull)
AddFolding (GetEndOfPrev(destructorDeclaration.Body.LBraceToken),
destructorDeclaration.Body.RBraceToken.EndLocation, true);
base.VisitDestructorDeclaration (destructorDeclaration);
}
public override void VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration)
{
if (!operatorDeclaration.Body.IsNull)
AddFolding (GetEndOfPrev(operatorDeclaration.Body.LBraceToken),
operatorDeclaration.Body.RBraceToken.EndLocation, true);
base.VisitOperatorDeclaration (operatorDeclaration);
}
public override void VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration)
{
if (!propertyDeclaration.LBraceToken.IsNull)
AddFolding (GetEndOfPrev(propertyDeclaration.LBraceToken),
propertyDeclaration.RBraceToken.EndLocation, true);
base.VisitPropertyDeclaration (propertyDeclaration);
}
public override void VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration)
{
if (!indexerDeclaration.LBraceToken.IsNull)
AddFolding (GetEndOfPrev(indexerDeclaration.LBraceToken),
indexerDeclaration.RBraceToken.EndLocation, true);
base.VisitIndexerDeclaration (indexerDeclaration);
}
public override void VisitCustomEventDeclaration (CustomEventDeclaration eventDeclaration)
{
if (!eventDeclaration.LBraceToken.IsNull)
AddFolding (GetEndOfPrev(eventDeclaration.LBraceToken),
eventDeclaration.RBraceToken.EndLocation, true);
base.VisitCustomEventDeclaration (eventDeclaration);
}
#endregion
#region Statements
public override void VisitSwitchStatement (SwitchStatement switchStatement)
{
if (!switchStatement.RBraceToken.IsNull)
AddFolding (GetEndOfPrev(switchStatement.LBraceToken),
switchStatement.RBraceToken.EndLocation);
base.VisitSwitchStatement (switchStatement);
}
public override void VisitBlockStatement (BlockStatement blockStatement)
{
if (!(blockStatement.Parent is EntityDeclaration) && blockStatement.EndLocation.Line - blockStatement.StartLocation.Line > 2) {
AddFolding (GetEndOfPrev(blockStatement), blockStatement.EndLocation);
}
base.VisitBlockStatement (blockStatement);
}
#endregion
#region Preprocessor directives
Stack<NewFolding> regions = new Stack<NewFolding>();
public override void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective)
{
switch (preProcessorDirective.Type) {
case PreProcessorDirectiveType.Region:
NewFolding folding = new NewFolding();
folding.DefaultClosed = true;
folding.Name = preProcessorDirective.Argument;
folding.StartOffset = GetOffset(preProcessorDirective.StartLocation);
regions.Push(folding);
break;
case PreProcessorDirectiveType.Endregion:
if (regions.Count > 0) {
folding = regions.Pop();
folding.EndOffset = GetOffset(preProcessorDirective.EndLocation);
foldings.Add(folding);
}
break;
}
}
#endregion
#region Comments
public override void VisitComment(Comment comment)
{
if (comment.CommentType == CommentType.InactiveCode)
return; // don't fold the inactive code comment; instead fold the preprocessor directives
if (AreTwoSinglelineCommentsInConsecutiveLines(comment.PrevSibling as Comment, comment))
return; // already handled by previous comment
Comment lastComment = comment;
Comment nextComment;
while (true) {
nextComment = lastComment.NextSibling as Comment;
if (!AreTwoSinglelineCommentsInConsecutiveLines(lastComment, nextComment))
break;
lastComment = nextComment;
}
if (lastComment.EndLocation.Line - comment.StartLocation.Line > 2) {
var folding = AddFolding(comment.StartLocation, lastComment.EndLocation);
if (folding != null) {
switch (comment.CommentType) {
case CommentType.SingleLine:
folding.Name = "// ...";
break;
case CommentType.MultiLine:
folding.Name = "/* ... */";
break;
case CommentType.Documentation:
folding.Name = "/// ...";
break;
case CommentType.MultiLineDocumentation:
folding.Name = "/** ... */";
break;
}
}
}
}
bool AreTwoSinglelineCommentsInConsecutiveLines(Comment comment1, Comment comment2)
{
if (comment1 == null || comment2 == null)
return false;
return comment1.CommentType == comment2.CommentType
&& comment1.StartLocation.Line == comment1.EndLocation.Line
&& comment1.EndLocation.Line + 1 == comment2.StartLocation.Line
&& comment1.StartLocation.Column == comment2.StartLocation.Column
&& comment2.StartLocation.Line == comment2.EndLocation.Line;
}
#endregion
}
}