| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.javascript2.jade.editor; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import org.netbeans.api.editor.fold.FoldType; |
| import org.netbeans.api.lexer.Token; |
| import org.netbeans.api.lexer.TokenHierarchy; |
| import org.netbeans.api.lexer.TokenSequence; |
| import org.netbeans.modules.csl.api.OffsetRange; |
| import org.netbeans.modules.csl.api.StructureItem; |
| import org.netbeans.modules.csl.api.StructureScanner; |
| import org.netbeans.modules.csl.spi.ParserResult; |
| import org.netbeans.modules.javascript2.jade.editor.lexer.JadeTokenId; |
| |
| /** |
| * |
| * @author Petr Pisl |
| */ |
| public class JadeStructureScanner implements StructureScanner { |
| |
| @Override |
| public List<? extends StructureItem> scan(ParserResult info) { |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public Map<String, List<OffsetRange>> folds(ParserResult info) { |
| Map<String, List<OffsetRange>> folds = new HashMap<>(); |
| TokenHierarchy th = info.getSnapshot().getTokenHierarchy(); |
| TokenSequence<JadeTokenId> ts = th.tokenSequence(JadeTokenId.jadeLanguage()); |
| |
| List<TokenSequence<?>> list = th.tokenSequenceList(ts.languagePath(), 0, info.getSnapshot().getText().length()); |
| |
| ts.moveStart(); |
| Token<JadeTokenId> token; |
| JadeTokenId id; |
| int indent = 0; |
| int commentDelStart = 0; |
| int commentDelLength = 0; |
| List<FoldingItem> stack = new ArrayList<FoldingItem>(); |
| boolean afterEOL = true; |
| while (ts.moveNext()) { |
| token = ts.token(); |
| id = token.id(); |
| if (afterEOL) { |
| if (id == JadeTokenId.WHITESPACE) { |
| indent = token.length(); |
| } else if (id == JadeTokenId.TAG || id == JadeTokenId.KEYWORD_BLOCK || id == JadeTokenId.KEYWORD_MIXIN) { |
| afterEOL = false; |
| stack.add(new FoldingItem(FoldType.TAG, indent, ts.offset(), ts.offset() + token.length())); |
| } else if (id != JadeTokenId.COMMENT_DELIMITER && id != JadeTokenId.UNBUFFERED_COMMENT_DELIMITER){ |
| afterEOL = false; |
| } else { |
| commentDelStart = ts.offset(); |
| commentDelLength = token.length(); |
| } |
| if (id == JadeTokenId.COMMENT || id == JadeTokenId.UNBUFFERED_COMMENT) { |
| String comment = token.text().toString(); |
| while (!comment.isEmpty() && comment.charAt(comment.length() - 1) == '\n') { |
| comment = comment.substring(0, comment.length() - 1); |
| } |
| if (comment.indexOf('\n') >= 0) { |
| stack.add(new FoldingItem(FoldType.COMMENT, indent, commentDelStart, commentDelStart + commentDelLength)); |
| } |
| afterEOL = true; |
| } |
| } |
| if (id == JadeTokenId.EOL) { |
| afterEOL = true; |
| indent = 0; |
| } |
| |
| } |
| if (!stack.isEmpty()) { |
| for(int i = 0; i < stack.size(); i++) { |
| FoldingItem item1 = stack.get(i); |
| boolean foldCreated = false; |
| for (int j = i + 1; j < stack.size(); j++) { |
| FoldingItem item2 = stack.get(j); |
| if (item1.indent >= item2.indent) { |
| foldCreated = true; |
| appendFold(info, folds, item1.type.code(), item1.tagEnd, item2.tagStart - item2.indent - 1); |
| break; |
| } |
| } |
| if (!foldCreated) { |
| appendFold(info, folds, FoldType.TAG.code(), item1.tagEnd, ts.offset() + ts.token().length()); |
| } |
| } |
| |
| } |
| return folds; |
| } |
| |
| private void appendFold(ParserResult info, Map<String, List<OffsetRange>> folds, String kind, int startOffset, int endOffset) { |
| if (startOffset >= 0 && endOffset >= startOffset) { |
| if (info.getSnapshot().getText().subSequence(startOffset, endOffset).toString().indexOf('\n') > -1) { |
| getRanges(folds, kind).add(new OffsetRange(startOffset, endOffset)); |
| } |
| } |
| } |
| |
| private List<OffsetRange> getRanges(Map<String, List<OffsetRange>> folds, String kind) { |
| List<OffsetRange> ranges = folds.get(kind); |
| if (ranges == null) { |
| ranges = new ArrayList<OffsetRange>(); |
| folds.put(kind, ranges); |
| } |
| return ranges; |
| } |
| |
| @Override |
| public Configuration getConfiguration() { |
| return null; |
| } |
| |
| private static class FoldingItem { |
| final int indent; |
| final int tagStart; |
| final int tagEnd; |
| final FoldType type; |
| |
| public FoldingItem(FoldType type, int indent, int tagStart, int tagEnd) { |
| this.indent = indent; |
| this.tagStart = tagStart; |
| this.tagEnd = tagEnd; |
| this.type = type; |
| } |
| |
| } |
| } |