/**
* Copyright (c) 2012 Cloudsmith Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cloudsmith
*
*/
package org.cloudsmith.geppetto.pp.dsl.ui.editor.folding;
import java.util.List;
import java.util.regex.Matcher;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.xtext.ui.editor.folding.DefaultFoldingRegionProvider;
import org.eclipse.xtext.ui.editor.folding.IFoldingRegionAcceptor;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.TerminalsTokenTypeToPartitionMapper;
import org.eclipse.xtext.util.ITextRegion;
import org.eclipse.xtext.util.TextRegion;
import com.google.common.collect.Lists;
/**
* A folding RegionProvider that provides folding of sequence of SL Comment
*
*/
public class PPFoldingRegionProvider extends DefaultFoldingRegionProvider {
private static final Logger log = Logger.getLogger(PPFoldingRegionProvider.class);
@Override
protected void computeCommentFolding(IXtextDocument xtextDocument,
IFoldingRegionAcceptor<ITextRegion> foldingRegionAcceptor) {
computeMLCommentFolding(xtextDocument, foldingRegionAcceptor);
computeSLCommentFolding(xtextDocument, foldingRegionAcceptor);
}
protected void computeMLCommentFolding(IXtextDocument xtextDocument,
IFoldingRegionAcceptor<ITextRegion> foldingRegionAcceptor) {
try {
ITypedRegion[] typedRegions = xtextDocument.computePartitioning(
IDocumentExtension3.DEFAULT_PARTITIONING, 0, xtextDocument.getLength(), false);
for(ITypedRegion typedRegion : typedRegions) {
if(TerminalsTokenTypeToPartitionMapper.COMMENT_PARTITION.equals(typedRegion.getType())) {
int offset = typedRegion.getOffset();
int length = typedRegion.getLength();
String content = xtextDocument.get(offset, length);
if(content.endsWith("\r\n"))
length -= 2;
else if(content.endsWith("\n"))
length -= 1;
Matcher matcher = getTextPatternInComment().matcher(content);
if(matcher.find()) {
TextRegion significant = new TextRegion(offset + matcher.start(), 0);
foldingRegionAcceptor.accept(offset, length, significant);
}
else {
foldingRegionAcceptor.accept(offset, length);
}
}
}
}
catch(BadLocationException e) {
log.error(e, e);
}
catch(BadPartitioningException e) {
log.error(e, e);
}
catch(AssertionFailedException e) {
// partioning failed
log.error(e, e);
}
}
/**
* @param xtextDocument
* @param foldingRegionAcceptor
*/
private void computeSLCommentFolding(IXtextDocument xtextDocument,
IFoldingRegionAcceptor<ITextRegion> foldingRegionAcceptor) {
try {
ITypedRegion[] typedRegions = xtextDocument.computePartitioning(
IDocumentExtension3.DEFAULT_PARTITIONING, 0, xtextDocument.getLength(), false);
List<ITypedRegion> slComments = Lists.newArrayList();
List<List<ITypedRegion>> commentGroups = Lists.newArrayList();
for(ITypedRegion typedRegion : typedRegions)
if(TerminalsTokenTypeToPartitionMapper.SL_COMMENT_PARTITION.equals(typedRegion.getType())) {
if(slComments.isEmpty())
slComments.add(typedRegion);
else {
int index = slComments.size() - 1;
ITypedRegion previous = slComments.get(index);
if(previous.getOffset() + previous.getLength() == typedRegion.getOffset()) {
slComments.add(typedRegion);
}
else {
// not a continuation, do we have a folding region?
if(slComments.size() > 1)
commentGroups.add(slComments);
slComments = Lists.newArrayList();
slComments.add(typedRegion);
}
}
}
if(slComments.size() > 1)
commentGroups.add(slComments);
for(List<ITypedRegion> group : commentGroups) {
int startOffset = -1;
int length = 0;
for(ITypedRegion typedRegion : group) {
if(startOffset == -1)
startOffset = typedRegion.getOffset();
length += typedRegion.getLength();
}
String content = xtextDocument.get(startOffset, length);
if(content.endsWith("\r\n"))
length -= 2;
else if(content.endsWith("\n"))
length -= 1;
Matcher matcher = getTextPatternInComment().matcher(content);
if(matcher.find()) {
TextRegion significant = new TextRegion(startOffset + matcher.start(), 0);
foldingRegionAcceptor.accept(startOffset, length, significant);
}
else {
foldingRegionAcceptor.accept(startOffset, length);
}
}
}
catch(BadLocationException e) {
log.error(e, e);
}
catch(BadPartitioningException e) {
log.error(e, e);
}
catch(AssertionFailedException e) {
// partitioning failed
log.error(e, e);
}
}
}