/**
* Aptana Studio
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
* Please see the license.html included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.editor.php.formatter;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org2.eclipse.php.internal.core.ast.nodes.Comment;
import org2.eclipse.php.internal.core.ast.nodes.Program;
import com.aptana.editor.php.formatter.nodes.FormatterPHPCommentNode;
import com.aptana.editor.php.internal.parser.nodes.PHPASTWrappingNode;
import com.aptana.formatter.FormatterDocument;
import com.aptana.formatter.IFormatterDocument;
import com.aptana.formatter.nodes.FormatterNodeRewriter;
import com.aptana.formatter.nodes.IFormatterContainerNode;
import com.aptana.formatter.nodes.IFormatterNode;
import com.aptana.parsing.ast.IParseNode;
import com.aptana.parsing.ast.IParseRootNode;
/**
* PHP Formatter node rewriter
*
* @author Shalom Gibly <sgibly@aptana.com>
*/
public class PHPFormatterNodeRewriter extends FormatterNodeRewriter
{
private static final Pattern COMMENT_LINE_PATTERN = Pattern.compile("(\\S.*)"); //$NON-NLS-1$
private static final String MULTI_LINE_COMMENT_PREFIX = "/*"; //$NON-NLS-1$
/**
* Constructs a new PHPFormatterNodeRewriter
*
* @param parseResultRoot
*/
public PHPFormatterNodeRewriter(IParseRootNode parseResultRoot, FormatterDocument document)
{
List<Comment> comments = null;
// the root node should hold a single Program (AST) that was inserted as a ParseNode.
if (parseResultRoot.getChildCount() == 1)
{
IParseNode child = parseResultRoot.getChild(0);
if (child instanceof PHPASTWrappingNode)
{
Program ast = ((PHPASTWrappingNode) child).getAST();
comments = ast.comments();
}
}
insertComments(document, comments);
}
private void insertComments(FormatterDocument document, List<Comment> comments)
{
for (Comment node : comments)
{
// in case we have a multi-line block comment, we actually break the comment to its lines and
// create a comment node for each line.
int startingOffset = node.getStart();
int endingOffset = node.getEnd();
String commentText = document.get(startingOffset, endingOffset);
if (commentText.startsWith(MULTI_LINE_COMMENT_PREFIX))
{
// Push each line as a comment. Mark the first line as a 'first'.
Matcher matcher = COMMENT_LINE_PATTERN.matcher(commentText);
boolean isFirstLine = true;
while (matcher.find())
{
int start = matcher.start();
int end = matcher.end();
addComment(startingOffset + start, startingOffset + end, new PHPCommentInfo(true, isFirstLine));
isFirstLine = false;
}
}
else
{
addComment(startingOffset, endingOffset, new PHPCommentInfo(false, false));
}
}
}
/*
* (non-Javadoc)
* @see com.aptana.formatter.nodes.FormatterNodeRewriter#rewrite(com.aptana.formatter.nodes.IFormatterContainerNode)
*/
@Override
public void rewrite(IFormatterContainerNode root)
{
super.rewrite(root);
attachComments(root);
}
/*
* (non-Javadoc)
* @see com.aptana.formatter.nodes.FormatterNodeRewriter#createCommentNode(com.aptana.formatter.IFormatterDocument,
* int, int, java.lang.Object)
*/
@Override
protected IFormatterNode createCommentNode(IFormatterDocument document, int startOffset, int endOffset,
Object object)
{
PHPCommentInfo info = (PHPCommentInfo) object;
return new FormatterPHPCommentNode(document, startOffset, endOffset, info.isMultiLine, info.isFirstLine);
}
private class PHPCommentInfo
{
boolean isMultiLine;
boolean isFirstLine;
PHPCommentInfo(boolean isMultiLine, boolean isFirstLine)
{
this.isMultiLine = isMultiLine;
this.isFirstLine = isFirstLine;
}
}
}