20
20
* @since 0.3.0
21
21
*/
22
22
public class OrgFoldingBuilder implements FoldingBuilder {
23
+
24
+ private final static Set <IElementType > BLOCK_ELEMENTS = new HashSet <IElementType >(Arrays .asList (
25
+ OrgTokenTypes .BLOCK ,
26
+ OrgTokenTypes .DRAWER ));
27
+
23
28
@ NotNull
24
29
@ Override
25
30
public FoldingDescriptor [] buildFoldRegions (@ NotNull ASTNode astNode , @ NotNull Document document ) {
@@ -35,19 +40,84 @@ public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode astNode, @NotNull D
35
40
*/
36
41
protected void collectBlocks (final ASTNode node , final List <FoldingDescriptor > descriptors ) {
37
42
final IElementType token = node .getElementType ();
38
- Set <IElementType > blockElements = new HashSet <IElementType >(Arrays .asList (
39
- OrgTokenTypes .BLOCK ,
40
- OrgTokenTypes .DRAWER ));
41
- if (blockElements .contains (token )) {
42
- final FoldingDescriptor descriptor = new FoldingDescriptor (node , node .getTextRange ());
43
- descriptors .add (descriptor );
43
+
44
+ if (isBlock (token )) {
45
+ foldBlock (node , descriptors );
46
+ } else if (isOutline (token )) {
47
+ foldOutline (node , descriptors );
44
48
}
45
49
46
50
for (ASTNode child : node .getChildren (null )) {
47
51
collectBlocks (child , descriptors );
48
52
}
49
53
}
50
54
55
+ private void foldOutline (ASTNode node , List <FoldingDescriptor > descriptors ) {
56
+ final ASTNode nextSibling = findNextOutline (node );
57
+ final TextRange textRange ;
58
+ if (nextSibling != null ) {
59
+ textRange = TextRange .create (node .getStartOffset (), nextSibling .getStartOffset () - 1 );
60
+ } else {
61
+ textRange = TextRange .create (node .getStartOffset (), getLastNode (node ).getStartOffset ());
62
+ }
63
+ final FoldingDescriptor descriptor = new FoldingDescriptor (node , textRange );
64
+ descriptors .add (descriptor );
65
+ }
66
+
67
+ private ASTNode getLastNode (ASTNode node ) {
68
+ return node .getTreeParent ().getLastChildNode ();
69
+ }
70
+
71
+ /**
72
+ * Find the next outline after the given node which has a depth equal or higher (-> less stars) than the current outline depth
73
+ * Also stops
74
+ * @param node The current outline node
75
+ * @return The node representing the next outline with a depth equal or higher (-> less stars) than the current one
76
+ */
77
+ private ASTNode findNextOutline (ASTNode node ) {
78
+ final int depth = outlineDepth (node .getText ());
79
+
80
+ ASTNode next = null ;
81
+ for (ASTNode candidate = node .getTreeNext (); candidate != null && next == null ; candidate = candidate .getTreeNext ()) {
82
+ if (isPeerOutline (depth , candidate )) {
83
+ next = candidate ;
84
+ }
85
+ }
86
+
87
+ return next ;
88
+ }
89
+
90
+ private boolean isPeerOutline (int depth , ASTNode candidate ) {
91
+ return isOutline (candidate .getElementType ()) && outlineDepth (candidate .getText ()) <= depth ;
92
+ }
93
+
94
+ /**
95
+ * Count how many stars are used in an outline, indicating its depth
96
+ *
97
+ * @param text The text of the outline
98
+ * @return The number of initial stars in the outline
99
+ */
100
+ private int outlineDepth (String text ) {
101
+ if (text .startsWith ("*" )) {
102
+ return text .split ("[^*]" )[0 ].length ();
103
+ } else {
104
+ return 0 ;
105
+ }
106
+ }
107
+
108
+ private void foldBlock (ASTNode node , List <FoldingDescriptor > descriptors ) {
109
+ final FoldingDescriptor descriptor = new FoldingDescriptor (node , node .getTextRange ());
110
+ descriptors .add (descriptor );
111
+ }
112
+
113
+ private boolean isOutline (IElementType token ) {
114
+ return OrgTokenTypes .OUTLINE .equals (token );
115
+ }
116
+
117
+ private boolean isBlock (IElementType token ) {
118
+ return BLOCK_ELEMENTS .contains (token );
119
+ }
120
+
51
121
@ Nullable
52
122
@ Override
53
123
public String getPlaceholderText (@ NotNull ASTNode astNode ) {
0 commit comments