|
14 | 14 |
|
15 | 15 | import com.google.common.collect.ImmutableMap; |
16 | 16 | import com.intellij.lang.ASTNode; |
17 | | -import com.intellij.lang.folding.FoldingBuilder; |
| 17 | +import com.intellij.lang.folding.CustomFoldingBuilder; |
18 | 18 | import com.intellij.lang.folding.FoldingDescriptor; |
19 | 19 | import com.intellij.openapi.editor.Document; |
20 | | -import com.intellij.openapi.project.DumbAware; |
21 | 20 | import com.intellij.openapi.util.Couple; |
22 | 21 | import com.intellij.openapi.util.TextRange; |
23 | 22 | import com.intellij.psi.PsiElement; |
|
32 | 31 | import io.protostuff.jetbrains.plugin.psi.OneOfNode; |
33 | 32 | import io.protostuff.jetbrains.plugin.psi.ServiceNode; |
34 | 33 | import io.protostuff.jetbrains.plugin.psi.TypeReferenceNode; |
35 | | -import java.util.ArrayList; |
36 | 34 | import java.util.List; |
37 | 35 | import java.util.Map; |
38 | 36 | import java.util.function.Function; |
|
44 | 42 | * |
45 | 43 | * @author Kostiantyn Shchepanovskyi |
46 | 44 | */ |
47 | | -public class ProtoFoldingBuilder implements FoldingBuilder, DumbAware { |
| 45 | +public class ProtoFoldingBuilder extends CustomFoldingBuilder { |
48 | 46 |
|
49 | 47 | private static final Map<IElementType, Function<ASTNode, String>> PROVIDERS = ImmutableMap.<IElementType, Function<ASTNode, String>>builder() |
50 | 48 | .put(rule(RULE_messageBlock), node -> { |
@@ -82,48 +80,6 @@ public class ProtoFoldingBuilder implements FoldingBuilder, DumbAware { |
82 | 80 | .put(token(COMMENT), node -> "/*...*/") |
83 | 81 | .build(); |
84 | 82 |
|
85 | | - @NotNull |
86 | | - @Override |
87 | | - public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) { |
88 | | - final List<FoldingDescriptor> descriptors = new ArrayList<>(); |
89 | | - collectDescriptorsRecursively(node, document, descriptors); |
90 | | - return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); |
91 | | - } |
92 | | - |
93 | | - @Nullable |
94 | | - @Override |
95 | | - public String getPlaceholderText(@NotNull ASTNode node) { |
96 | | - final IElementType type = node.getElementType(); |
97 | | - Function<ASTNode, String> provider = PROVIDERS.getOrDefault(type, ast -> "..."); |
98 | | - return provider.apply(node); |
99 | | - } |
100 | | - |
101 | | - @Override |
102 | | - public boolean isCollapsedByDefault(@NotNull ASTNode node) { |
103 | | - // This code should collapse header comments. |
104 | | - // However, in most of the cases it will not work, |
105 | | - // as when file is open caret is at the beginning of the document, |
106 | | - // thus preventing collapsing it. |
107 | | - // TODO: Collapse header comment when file is opened |
108 | | - return node.getTreeParent() instanceof FileElement |
109 | | - && findPreviousNonWhitespaceOrCommentNode(node) == null; |
110 | | - } |
111 | | - |
112 | | - @Nullable |
113 | | - private ASTNode findPreviousNonWhitespaceOrCommentNode(@NotNull ASTNode node) { |
114 | | - ASTNode tmp = node; |
115 | | - while (tmp != null) { |
116 | | - IElementType type = tmp.getElementType(); |
117 | | - if (!(tmp instanceof PsiWhiteSpace |
118 | | - || type == token(COMMENT) |
119 | | - || type == token(LINE_COMMENT))) { |
120 | | - break; |
121 | | - } |
122 | | - tmp = tmp.getTreePrev(); |
123 | | - } |
124 | | - return tmp; |
125 | | - } |
126 | | - |
127 | 83 | private static void collectDescriptorsRecursively(@NotNull ASTNode node, |
128 | 84 | @NotNull Document document, |
129 | 85 | @NotNull List<FoldingDescriptor> descriptors) { |
@@ -179,4 +135,42 @@ private static boolean spanMultipleLines(@NotNull ASTNode node, @NotNull Documen |
179 | 135 | final TextRange range = node.getTextRange(); |
180 | 136 | return document.getLineNumber(range.getStartOffset()) < document.getLineNumber(range.getEndOffset()); |
181 | 137 | } |
| 138 | + |
| 139 | + @Override |
| 140 | + protected void buildLanguageFoldRegions(@NotNull List<FoldingDescriptor> descriptors, @NotNull PsiElement root, @NotNull Document document, boolean quick) { |
| 141 | + collectDescriptorsRecursively(root.getNode(), document, descriptors); |
| 142 | + } |
| 143 | + |
| 144 | + @Override |
| 145 | + protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { |
| 146 | + final IElementType type = node.getElementType(); |
| 147 | + Function<ASTNode, String> provider = PROVIDERS.getOrDefault(type, ast -> "..."); |
| 148 | + return provider.apply(node); |
| 149 | + } |
| 150 | + |
| 151 | + @Override |
| 152 | + protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) { |
| 153 | + // This code should collapse header comments. |
| 154 | + // However, in most of the cases it will not work, |
| 155 | + // as when file is open caret is at the beginning of the document, |
| 156 | + // thus preventing collapsing it. |
| 157 | + // TODO: Collapse header comment when file is opened |
| 158 | + return node.getTreeParent() instanceof FileElement |
| 159 | + && findPreviousNonWhitespaceOrCommentNode(node) == null; |
| 160 | + } |
| 161 | + |
| 162 | + @Nullable |
| 163 | + private ASTNode findPreviousNonWhitespaceOrCommentNode(@NotNull ASTNode node) { |
| 164 | + ASTNode tmp = node; |
| 165 | + while (tmp != null) { |
| 166 | + IElementType type = tmp.getElementType(); |
| 167 | + if (!(tmp instanceof PsiWhiteSpace |
| 168 | + || type == token(COMMENT) |
| 169 | + || type == token(LINE_COMMENT))) { |
| 170 | + break; |
| 171 | + } |
| 172 | + tmp = tmp.getTreePrev(); |
| 173 | + } |
| 174 | + return tmp; |
| 175 | + } |
182 | 176 | } |
0 commit comments