Changeset 14927 for branches/PersistenceReintegration/HeuristicLab.CodeEditor/3.4/LanguageFeatures/CodeFolding
- Timestamp:
- 05/04/17 17:19:35 (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/PersistenceReintegration/HeuristicLab.CodeEditor/3.4/LanguageFeatures/CodeFolding/CSharp/FoldingVisitor.cs
r11700 r14927 28 28 namespace CSharpBinding.Parser 29 29 { 30 // TODO: move this class + NewFolding to NRefactory 31 class FoldingVisitor : DepthFirstAstVisitor 32 { 33 internal List<NewFolding> foldings = new List<NewFolding> (); 34 internal IDocument document; 35 36 int GetOffset(TextLocation location) 37 { 38 return document.GetOffset(location); 39 } 40 41 NewFolding AddFolding(TextLocation start, TextLocation end, bool isDefinition = false) 42 { 43 if (end.Line <= start.Line || start.IsEmpty || end.IsEmpty) 44 return null; 45 NewFolding folding = new NewFolding(GetOffset(start), GetOffset(end)); 46 folding.IsDefinition = isDefinition; 47 foldings.Add(folding); 48 return folding; 49 } 50 51 TextLocation GetEndOfPrev(AstNode node) 52 { 53 do { 54 node = node.GetPrevNode(); 55 } while (node.NodeType == NodeType.Whitespace); 56 return node.EndLocation; 57 } 58 59 #region usings 60 void AddUsings (AstNode parent) 61 { 62 var firstChild = parent.Children.FirstOrDefault (child => child is UsingDeclaration || child is UsingAliasDeclaration); 63 var node = firstChild; 64 while (node != null) { 65 var next = node.GetNextNode (); 66 if (next is UsingDeclaration || next is UsingAliasDeclaration) { 67 node = next; 68 } else { 69 break; 70 } 71 } 72 if (firstChild != node) { 73 NewFolding folding = AddFolding(firstChild.StartLocation, node.EndLocation); 74 if (folding != null) { 75 folding.Name = "using..."; 76 folding.DefaultClosed = true; 77 } 78 } 79 } 80 public override void VisitSyntaxTree (SyntaxTree unit) 81 { 82 AddUsings (unit); 83 base.VisitSyntaxTree (unit); 84 } 85 86 public override void VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration) 87 { 88 AddUsings (namespaceDeclaration); 89 if (!namespaceDeclaration.RBraceToken.IsNull) 90 AddFolding (namespaceDeclaration.LBraceToken.GetPrevNode ().EndLocation, namespaceDeclaration.RBraceToken.EndLocation); 91 base.VisitNamespaceDeclaration (namespaceDeclaration); 92 } 93 #endregion 94 95 #region Entity Declarations 96 public override void VisitTypeDeclaration (TypeDeclaration typeDeclaration) 97 { 98 if (!typeDeclaration.RBraceToken.IsNull) 99 AddFolding (GetEndOfPrev(typeDeclaration.LBraceToken), typeDeclaration.RBraceToken.EndLocation); 100 base.VisitTypeDeclaration (typeDeclaration); 101 } 102 103 public override void VisitMethodDeclaration (MethodDeclaration methodDeclaration) 104 { 105 if (!methodDeclaration.Body.IsNull) { 106 AddFolding (GetEndOfPrev(methodDeclaration.Body.LBraceToken), 107 methodDeclaration.Body.RBraceToken.EndLocation, true); 108 } 109 base.VisitMethodDeclaration (methodDeclaration); 110 } 111 112 public override void VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration) 113 { 114 if (!constructorDeclaration.Body.IsNull) 115 AddFolding (GetEndOfPrev(constructorDeclaration.Body.LBraceToken), 116 constructorDeclaration.Body.RBraceToken.EndLocation, true); 117 base.VisitConstructorDeclaration (constructorDeclaration); 118 } 119 120 public override void VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration) 121 { 122 if (!destructorDeclaration.Body.IsNull) 123 AddFolding (GetEndOfPrev(destructorDeclaration.Body.LBraceToken), 124 destructorDeclaration.Body.RBraceToken.EndLocation, true); 125 base.VisitDestructorDeclaration (destructorDeclaration); 126 } 127 128 public override void VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration) 129 { 130 if (!operatorDeclaration.Body.IsNull) 131 AddFolding (GetEndOfPrev(operatorDeclaration.Body.LBraceToken), 132 operatorDeclaration.Body.RBraceToken.EndLocation, true); 133 base.VisitOperatorDeclaration (operatorDeclaration); 134 } 135 136 public override void VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration) 137 { 138 if (!propertyDeclaration.LBraceToken.IsNull) 139 AddFolding (GetEndOfPrev(propertyDeclaration.LBraceToken), 140 propertyDeclaration.RBraceToken.EndLocation, true); 141 base.VisitPropertyDeclaration (propertyDeclaration); 142 } 143 144 public override void VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration) 145 { 146 if (!indexerDeclaration.LBraceToken.IsNull) 147 AddFolding (GetEndOfPrev(indexerDeclaration.LBraceToken), 148 indexerDeclaration.RBraceToken.EndLocation, true); 149 base.VisitIndexerDeclaration (indexerDeclaration); 150 } 151 152 public override void VisitCustomEventDeclaration (CustomEventDeclaration eventDeclaration) 153 { 154 if (!eventDeclaration.LBraceToken.IsNull) 155 AddFolding (GetEndOfPrev(eventDeclaration.LBraceToken), 156 eventDeclaration.RBraceToken.EndLocation, true); 157 base.VisitCustomEventDeclaration (eventDeclaration); 158 } 159 #endregion 160 161 #region Statements 162 public override void VisitSwitchStatement (SwitchStatement switchStatement) 163 { 164 if (!switchStatement.RBraceToken.IsNull) 165 AddFolding (GetEndOfPrev(switchStatement.LBraceToken), 166 switchStatement.RBraceToken.EndLocation); 167 base.VisitSwitchStatement (switchStatement); 168 } 169 170 public override void VisitBlockStatement (BlockStatement blockStatement) 171 { 172 if (!(blockStatement.Parent is EntityDeclaration) && blockStatement.EndLocation.Line - blockStatement.StartLocation.Line > 2) { 173 AddFolding (GetEndOfPrev(blockStatement), blockStatement.EndLocation); 174 } 175 176 base.VisitBlockStatement (blockStatement); 177 } 178 #endregion 179 180 #region Preprocessor directives 181 Stack<NewFolding> regions = new Stack<NewFolding>(); 182 183 public override void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective) 184 { 185 switch (preProcessorDirective.Type) { 186 case PreProcessorDirectiveType.Region: 187 NewFolding folding = new NewFolding(); 188 folding.DefaultClosed = true; 189 folding.Name = preProcessorDirective.Argument; 190 folding.StartOffset = GetOffset(preProcessorDirective.StartLocation); 191 regions.Push(folding); 192 break; 193 case PreProcessorDirectiveType.Endregion: 194 if (regions.Count > 0) { 195 folding = regions.Pop(); 196 folding.EndOffset = GetOffset(preProcessorDirective.EndLocation); 197 foldings.Add(folding); 198 } 199 break; 200 } 201 } 202 #endregion 203 204 #region Comments 205 public override void VisitComment(Comment comment) 206 { 207 if (comment.CommentType == CommentType.InactiveCode) 208 return; // don't fold the inactive code comment; instead fold the preprocessor directives 209 if (AreTwoSinglelineCommentsInConsecutiveLines(comment.PrevSibling as Comment, comment)) 210 return; // already handled by previous comment 211 Comment lastComment = comment; 212 Comment nextComment; 213 while (true) { 214 nextComment = lastComment.NextSibling as Comment; 215 if (!AreTwoSinglelineCommentsInConsecutiveLines(lastComment, nextComment)) 216 break; 217 lastComment = nextComment; 218 } 219 if (lastComment.EndLocation.Line - comment.StartLocation.Line > 2) { 220 var folding = AddFolding(comment.StartLocation, lastComment.EndLocation); 221 if (folding != null) { 222 switch (comment.CommentType) { 223 case CommentType.SingleLine: 224 folding.Name = "// ..."; 225 break; 226 case CommentType.MultiLine: 227 folding.Name = "/* ... */"; 228 break; 229 case CommentType.Documentation: 230 folding.Name = "/// ..."; 231 break; 232 case CommentType.MultiLineDocumentation: 233 folding.Name = "/** ... */"; 234 break; 235 } 236 } 237 } 238 } 239 240 bool AreTwoSinglelineCommentsInConsecutiveLines(Comment comment1, Comment comment2) 241 { 242 if (comment1 == null || comment2 == null) 243 return false; 244 return comment1.CommentType == comment2.CommentType 245 && comment1.StartLocation.Line == comment1.EndLocation.Line 246 && comment1.EndLocation.Line + 1 == comment2.StartLocation.Line 247 && comment1.StartLocation.Column == comment2.StartLocation.Column 248 && comment2.StartLocation.Line == comment2.EndLocation.Line; 249 } 250 #endregion 251 } 30 // TODO: move this class + NewFolding to NRefactory 31 class FoldingVisitor : DepthFirstAstVisitor { 32 internal List<NewFolding> foldings = new List<NewFolding>(); 33 internal IDocument document; 34 35 int GetOffset(TextLocation location) { 36 return document.GetOffset(location); 37 } 38 39 NewFolding AddFolding(TextLocation start, TextLocation end, bool isDefinition = false) { 40 if (end.Line <= start.Line || start.IsEmpty || end.IsEmpty) 41 return null; 42 NewFolding folding = new NewFolding(GetOffset(start), GetOffset(end)); 43 folding.IsDefinition = isDefinition; 44 foldings.Add(folding); 45 return folding; 46 } 47 48 TextLocation GetEndOfPrev(AstNode node) { 49 do { 50 node = node.GetPrevNode(); 51 } while (node.NodeType == NodeType.Whitespace); 52 return node.EndLocation; 53 } 54 55 #region usings 56 void AddUsings(AstNode parent) { 57 var firstChild = parent.Children.FirstOrDefault(child => child is UsingDeclaration || child is UsingAliasDeclaration); 58 var node = firstChild; 59 while (node != null) { 60 var next = node.GetNextNode(); 61 if (next is UsingDeclaration || next is UsingAliasDeclaration) { 62 node = next; 63 } else { 64 break; 65 } 66 } 67 if (firstChild != node) { 68 NewFolding folding = AddFolding(firstChild.StartLocation, node.EndLocation); 69 if (folding != null) { 70 folding.Name = "using..."; 71 folding.DefaultClosed = true; 72 } 73 } 74 } 75 public override void VisitSyntaxTree(SyntaxTree unit) { 76 AddUsings(unit); 77 base.VisitSyntaxTree(unit); 78 } 79 80 public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) { 81 AddUsings(namespaceDeclaration); 82 if (!namespaceDeclaration.RBraceToken.IsNull) 83 AddFolding(namespaceDeclaration.LBraceToken.GetPrevNode().EndLocation, namespaceDeclaration.RBraceToken.EndLocation); 84 base.VisitNamespaceDeclaration(namespaceDeclaration); 85 } 86 #endregion 87 88 #region Entity Declarations 89 public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) { 90 if (!typeDeclaration.RBraceToken.IsNull) 91 AddFolding(GetEndOfPrev(typeDeclaration.LBraceToken), typeDeclaration.RBraceToken.EndLocation); 92 base.VisitTypeDeclaration(typeDeclaration); 93 } 94 95 public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) { 96 if (!methodDeclaration.Body.IsNull) { 97 AddFolding(GetEndOfPrev(methodDeclaration.Body.LBraceToken), 98 methodDeclaration.Body.RBraceToken.EndLocation, true); 99 } 100 base.VisitMethodDeclaration(methodDeclaration); 101 } 102 103 public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) { 104 if (!constructorDeclaration.Body.IsNull) 105 AddFolding(GetEndOfPrev(constructorDeclaration.Body.LBraceToken), 106 constructorDeclaration.Body.RBraceToken.EndLocation, true); 107 base.VisitConstructorDeclaration(constructorDeclaration); 108 } 109 110 public override void VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration) { 111 if (!destructorDeclaration.Body.IsNull) 112 AddFolding(GetEndOfPrev(destructorDeclaration.Body.LBraceToken), 113 destructorDeclaration.Body.RBraceToken.EndLocation, true); 114 base.VisitDestructorDeclaration(destructorDeclaration); 115 } 116 117 public override void VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration) { 118 if (!operatorDeclaration.Body.IsNull) 119 AddFolding(GetEndOfPrev(operatorDeclaration.Body.LBraceToken), 120 operatorDeclaration.Body.RBraceToken.EndLocation, true); 121 base.VisitOperatorDeclaration(operatorDeclaration); 122 } 123 124 public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) { 125 if (!propertyDeclaration.LBraceToken.IsNull) 126 AddFolding(GetEndOfPrev(propertyDeclaration.LBraceToken), 127 propertyDeclaration.RBraceToken.EndLocation, true); 128 base.VisitPropertyDeclaration(propertyDeclaration); 129 } 130 131 public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) { 132 if (!indexerDeclaration.LBraceToken.IsNull) 133 AddFolding(GetEndOfPrev(indexerDeclaration.LBraceToken), 134 indexerDeclaration.RBraceToken.EndLocation, true); 135 base.VisitIndexerDeclaration(indexerDeclaration); 136 } 137 138 public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) { 139 if (!eventDeclaration.LBraceToken.IsNull) 140 AddFolding(GetEndOfPrev(eventDeclaration.LBraceToken), 141 eventDeclaration.RBraceToken.EndLocation, true); 142 base.VisitCustomEventDeclaration(eventDeclaration); 143 } 144 #endregion 145 146 #region Statements 147 public override void VisitSwitchStatement(SwitchStatement switchStatement) { 148 if (!switchStatement.RBraceToken.IsNull) 149 AddFolding(GetEndOfPrev(switchStatement.LBraceToken), 150 switchStatement.RBraceToken.EndLocation); 151 base.VisitSwitchStatement(switchStatement); 152 } 153 154 public override void VisitBlockStatement(BlockStatement blockStatement) { 155 if (!(blockStatement.Parent is EntityDeclaration) && blockStatement.EndLocation.Line - blockStatement.StartLocation.Line > 2) { 156 AddFolding(GetEndOfPrev(blockStatement), blockStatement.EndLocation); 157 } 158 159 base.VisitBlockStatement(blockStatement); 160 } 161 #endregion 162 163 #region Preprocessor directives 164 Stack<NewFolding> regions = new Stack<NewFolding>(); 165 166 public override void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective) { 167 switch (preProcessorDirective.Type) { 168 case PreProcessorDirectiveType.Region: 169 NewFolding folding = new NewFolding(); 170 folding.DefaultClosed = true; 171 folding.Name = preProcessorDirective.Argument; 172 folding.StartOffset = GetOffset(preProcessorDirective.StartLocation); 173 regions.Push(folding); 174 break; 175 case PreProcessorDirectiveType.Endregion: 176 if (regions.Count > 0) { 177 folding = regions.Pop(); 178 folding.EndOffset = GetOffset(preProcessorDirective.EndLocation); 179 foldings.Add(folding); 180 } 181 break; 182 } 183 } 184 #endregion 185 186 #region Comments 187 public override void VisitComment(Comment comment) { 188 if (comment.CommentType == CommentType.InactiveCode) 189 return; // don't fold the inactive code comment; instead fold the preprocessor directives 190 if (AreTwoSinglelineCommentsInConsecutiveLines(comment.PrevSibling as Comment, comment)) 191 return; // already handled by previous comment 192 Comment lastComment = comment; 193 Comment nextComment; 194 while (true) { 195 nextComment = lastComment.NextSibling as Comment; 196 if (!AreTwoSinglelineCommentsInConsecutiveLines(lastComment, nextComment)) 197 break; 198 lastComment = nextComment; 199 } 200 if (lastComment.EndLocation.Line - comment.StartLocation.Line > 2) { 201 var folding = AddFolding(comment.StartLocation, lastComment.EndLocation); 202 if (folding != null) { 203 switch (comment.CommentType) { 204 case CommentType.SingleLine: 205 folding.Name = "// ..."; 206 break; 207 case CommentType.MultiLine: 208 folding.Name = "/* ... */"; 209 break; 210 case CommentType.Documentation: 211 folding.Name = "/// ..."; 212 break; 213 case CommentType.MultiLineDocumentation: 214 folding.Name = "/** ... */"; 215 break; 216 } 217 } 218 } 219 } 220 221 bool AreTwoSinglelineCommentsInConsecutiveLines(Comment comment1, Comment comment2) { 222 if (comment1 == null || comment2 == null) 223 return false; 224 return comment1.CommentType == comment2.CommentType 225 && comment1.StartLocation.Line == comment1.EndLocation.Line 226 && comment1.EndLocation.Line + 1 == comment2.StartLocation.Line 227 && comment1.StartLocation.Column == comment2.StartLocation.Column 228 && comment2.StartLocation.Line == comment2.EndLocation.Line; 229 } 230 #endregion 231 } 252 232 }
Note: See TracChangeset
for help on using the changeset viewer.