/*******************************************************************************
* Copyright (c) 2010 Martin Schnabel <mb0@mb0.org>.
* 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
******************************************************************************/
package org.axdt.as3.ui.folding;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.axdt.as3.model.As3Class;
import org.axdt.as3.model.As3ImportList;
import org.axdt.as3.model.As3Operation;
import org.axdt.as3.model.As3Package;
import org.axdt.as3.model.As3Program;
import org.axdt.as3.model.As3Type;
import org.axdt.as3.ui.folding.As3FoldedPosition.Acceptor;
import org.axdt.as3.ui.preferences.As3EditorPreferences;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
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.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.ILocationInFileProvider;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.folding.DefaultFoldingRegionProvider;
import org.eclipse.xtext.ui.editor.folding.FoldedPosition;
import org.eclipse.xtext.ui.editor.folding.IFoldingRegionProvider;
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 org.eclipse.xtext.util.concurrent.IUnitOfWork;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
public class As3FoldingRegionProvider implements IFoldingRegionProvider {
private static final Logger log = Logger.getLogger(DefaultFoldingRegionProvider.class);
protected static final Pattern TEXT_PATTERN_IN_COMMENT = Pattern.compile("\\w");
@Inject
protected As3EditorPreferences preferences;
@Inject
private ILocationInFileProvider locationInFileProvider;
public Collection<FoldedPosition> getFoldingRegions(final IXtextDocument xtextDocument) {
return xtextDocument.readOnly(new IUnitOfWork<Collection<FoldedPosition>, XtextResource>() {
public Collection<FoldedPosition> exec(XtextResource xtextResource) throws Exception {
if (xtextResource == null)
return Collections.emptyList();
return doGetFoldingRegions(xtextDocument, xtextResource);
}
});
}
protected Collection<FoldedPosition> doGetFoldingRegions(
IXtextDocument xtextDocument, XtextResource xtextResource) {
Collection<FoldedPosition> result = Sets.newLinkedHashSet();
if (preferences.getStore().getBoolean(As3EditorPreferences.USE_FOLDING)) {
Acceptor acceptor = new Acceptor(xtextDocument, result);
computeObjectFolding(xtextResource, acceptor);
computeCommentFolding(xtextDocument, acceptor);
}
return result;
}
protected void doHandle(EObject eObject, Acceptor acceptor) {
String type = null;
if (eObject instanceof As3Operation)
type = As3EditorPreferences.FOLD_MEMBERS;
else if (eObject instanceof As3ImportList)
type = As3EditorPreferences.FOLD_IMPORTS;
else if (!(eObject instanceof As3Type)) return;
computeObjectFolding(eObject, acceptor, type);
}
protected boolean shouldProcessContent(EObject eObject, Acceptor acceptor) {
if (eObject instanceof As3Package) {
ICompositeNode node = NodeModelUtils.getNode(eObject);
acceptor.setHeader(node.getOffset());
return true;
}
return eObject instanceof As3Class
|| eObject instanceof As3Program;
}
protected void computeCommentFolding(IXtextDocument xtextDocument, Acceptor acceptor) {
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();
Matcher matcher = TEXT_PATTERN_IN_COMMENT.matcher(xtextDocument.get(offset, length));
TextRegion significant = matcher.find() ? new TextRegion(offset + matcher.start(), 0) : null;
String type = offset < acceptor.getHeader()
? As3EditorPreferences.FOLD_HEADERS
: As3EditorPreferences.FOLD_COMMENTS;
acceptor.accept(offset, length, significant, type);
}
}
} catch (BadLocationException e) {
log.error(e, e);
} catch (BadPartitioningException e) {
log.error(e, e);
}
}
protected void computeObjectFolding(XtextResource xtextResource, Acceptor acceptor) {
TreeIterator<EObject> allContents = xtextResource.getAllContents();
while (allContents.hasNext()) {
EObject eObject = allContents.next();
doHandle(eObject, acceptor);
if (!shouldProcessContent(eObject, acceptor))
allContents.prune();
}
}
protected void computeObjectFolding(EObject eObject, Acceptor acceptor, String type) {
ITextRegion region = locationInFileProvider.getFullTextRegion(eObject);
if (region != null) {
ITextRegion significant = null;
if (!(eObject instanceof As3ImportList))
significant = locationInFileProvider.getSignificantTextRegion(eObject);
int offset = region.getOffset();
acceptor.accept(offset, region.getLength(), significant, type);
}
}
}