Skip to content

Commit 5acadf1

Browse files
committed
Added support for outline folding
Signed-off-by: Carlo Sciolla <carlo.sciolla@gmail.com>
1 parent 316e202 commit 5acadf1

File tree

1 file changed

+76
-6
lines changed

1 file changed

+76
-6
lines changed

src/main/java/tk/skuro/idea/orgmode/editor/folding/OrgFoldingBuilder.java

+76-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
* @since 0.3.0
2121
*/
2222
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+
2328
@NotNull
2429
@Override
2530
public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode astNode, @NotNull Document document) {
@@ -35,19 +40,84 @@ public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode astNode, @NotNull D
3540
*/
3641
protected void collectBlocks(final ASTNode node, final List<FoldingDescriptor> descriptors) {
3742
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);
4448
}
4549

4650
for(ASTNode child : node.getChildren(null)) {
4751
collectBlocks(child, descriptors);
4852
}
4953
}
5054

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+
51121
@Nullable
52122
@Override
53123
public String getPlaceholderText(@NotNull ASTNode astNode) {

0 commit comments

Comments
 (0)