blob: d9760751642b52694ee34154a719e9472a4d4d67 [file] [log] [blame]
/*
* 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;
}
}
}