blob: 7866f997c28803a7a5278907e472e7be915b100e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 xored software, Inc.
*
* 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:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.formatter;
import java.util.ArrayList;
import java.util.List;
public abstract class FormatterNodeRewriter {
protected void mergeTextNodes(IFormatterContainerNode root) {
final List<IFormatterNode> body = root.getBody();
final List<IFormatterNode> newBody = new ArrayList<IFormatterNode>();
final List<IFormatterNode> texts = new ArrayList<IFormatterNode>();
for (final IFormatterNode node : body) {
if (isPlainTextNode(node)) {
if (!texts.isEmpty()
&& ((IFormatterTextNode) texts.get(texts.size() - 1))
.getEndOffset() != node.getStartOffset()) {
flushTextNodes(texts, newBody);
}
texts.add(node);
} else {
if (!texts.isEmpty()) {
flushTextNodes(texts, newBody);
}
newBody.add(node);
}
}
if (!texts.isEmpty()) {
flushTextNodes(texts, newBody);
}
if (body.size() != newBody.size()) {
body.clear();
body.addAll(newBody);
}
for (final IFormatterNode node : body) {
if (node instanceof IFormatterContainerNode) {
mergeTextNodes((IFormatterContainerNode) node);
}
}
}
private void flushTextNodes(List<IFormatterNode> texts,
List<IFormatterNode> newBody) {
if (texts.size() > 1) {
final IFormatterNode first = texts.get(0);
final IFormatterNode last = texts.get(texts.size() - 1);
newBody.add(new FormatterTextNode(first.getDocument(), first
.getStartOffset(), last.getEndOffset()));
} else {
newBody.addAll(texts);
}
texts.clear();
}
protected boolean isPlainTextNode(final IFormatterNode node) {
return node.getClass() == FormatterTextNode.class;
}
private static class CommentInfo {
final int startOffset;
final int endOffset;
final Object object;
public CommentInfo(int startOffset, int endOffset, Object object) {
this.startOffset = startOffset;
this.endOffset = endOffset;
this.object = object;
}
}
private final List<CommentInfo> comments = new ArrayList<CommentInfo>();
protected void addComment(int startOffset, int endOffset, Object object) {
comments.add(new CommentInfo(startOffset, endOffset, object));
}
protected void insertComments(IFormatterContainerNode root) {
final List<IFormatterNode> body = root.getBody();
final List<IFormatterNode> newBody = new ArrayList<IFormatterNode>();
boolean changes = false;
for (final IFormatterNode node : body) {
if (isPlainTextNode(node)) {
if (hasComments(node.getStartOffset(), node.getEndOffset())) {
selectValidRanges(root.getDocument(),
node.getStartOffset(), node.getEndOffset(), newBody);
changes = true;
} else {
newBody.add(node);
}
} else {
newBody.add(node);
}
}
if (changes) {
body.clear();
body.addAll(newBody);
}
for (final IFormatterNode node : body) {
if (node instanceof IFormatterContainerNode) {
insertComments((IFormatterContainerNode) node);
}
}
}
private boolean hasComments(int startOffset, int endOffset) {
for (final CommentInfo commentNode : comments) {
if (commentNode.startOffset < endOffset
&& startOffset < commentNode.endOffset) {
return true;
}
}
return false;
}
private void selectValidRanges(IFormatterDocument document, int start,
int end, List<IFormatterNode> result) {
for (final CommentInfo comment : comments) {
if (start <= comment.endOffset && comment.startOffset <= end) {
if (start < comment.startOffset) {
int validEnd = Math.min(end, comment.startOffset);
result
.add(new FormatterTextNode(document, start,
validEnd));
start = comment.startOffset;
}
result.add(createCommentNode(document, start, Math.min(
comment.endOffset, end), comment.object));
start = comment.endOffset;
if (start > end) {
break;
}
}
}
if (start < end) {
result.add(new FormatterTextNode(document, start, end));
}
}
protected abstract IFormatterNode createCommentNode(
IFormatterDocument document, int startOffset, int endOffset,
Object object);
}