package com.redhat.ceylon.eclipse.code.editor;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getSelection;
import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.utilJ2C;
import static com.redhat.ceylon.eclipse.util.Nodes.findDeclarationWithBody;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ltk.core.refactoring.DocumentChange;
import org.eclipse.text.edits.ReplaceEdit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;
import com.redhat.ceylon.eclipse.util.EditorUtil;
import com.redhat.ceylon.eclipse.util.Nodes;
final class FormatBlockAction extends Action {
private final CeylonEditor editor;
FormatBlockAction(CeylonEditor editor) {
super(null);
this.editor = editor;
}
@Override
public void run() {
IDocument document = editor.getCeylonSourceViewer().getDocument();
final ITextSelection ts = getSelection(editor);
CeylonParseController pc = editor.getParseController();
Tree.CompilationUnit rootNode = pc.getParsedRootNode();
if (rootNode==null) return;
class FindBodyVisitor extends Visitor {
Node result;
private void handle(Node that) {
if (ts.getOffset()>=that.getStartIndex() &&
ts.getOffset()+ts.getLength()<=that.getEndIndex()) {
result = that;
}
}
@Override
public void visit(Tree.Body that) {
handle(that);
super.visit(that);
}
@Override
public void visit(Tree.NamedArgumentList that) {
handle(that);
super.visit(that);
}
@Override
public void visit(Tree.ImportMemberOrTypeList that) {
handle(that);
super.visit(that);
}
}
FindBodyVisitor fbv = new FindBodyVisitor();
fbv.visit(rootNode);
StringBuilder builder = new StringBuilder();
Node bodyNode = fbv.result;
if (bodyNode instanceof Tree.Body) {
Tree.Body body = (Tree.Body) bodyNode;
Tree.Declaration bodyDec =
findDeclarationWithBody(rootNode, body);
String bodyIndent =
utilJ2C().indents().getIndent(bodyDec, document);
String indent = bodyIndent + utilJ2C().indents().getDefaultIndent();
String delim = utilJ2C().indents().getDefaultLineDelimiter(document);
if (!body.getStatements().isEmpty()) {
builder.append(delim);
for (Tree.Statement st: body.getStatements()) {
builder.append(indent)
.append(Nodes.text(st, pc.getTokens()))
.append(delim);
}
builder.append(bodyIndent);
}
}
else if (bodyNode instanceof Tree.NamedArgumentList) {
Tree.NamedArgumentList body =
(Tree.NamedArgumentList) bodyNode;
String bodyIndent = utilJ2C().indents().getIndent(body, document);
String indent = bodyIndent + utilJ2C().indents().getDefaultIndent();
String delim = utilJ2C().indents().getDefaultLineDelimiter(document);
if (!body.getNamedArguments().isEmpty()) {
for (Tree.NamedArgument st:
body.getNamedArguments()) {
builder.append(indent)
.append(Nodes.text(st, pc.getTokens()))
.append(delim);
}
}
Tree.SequencedArgument sequencedArg =
body.getSequencedArgument();
if (sequencedArg!=null) {
builder.append(indent)
.append(Nodes.text(sequencedArg,
pc.getTokens()))
.append(delim);
}
if (builder.length()!=0) {
builder.insert(0, delim);
builder.append(bodyIndent);
}
}
else if (bodyNode instanceof Tree.ImportMemberOrTypeList) {
Tree.ImportMemberOrTypeList body =
(Tree.ImportMemberOrTypeList) bodyNode;
String bodyIndent = utilJ2C().indents().getIndent(body, document);
String indent = bodyIndent + utilJ2C().indents().getDefaultIndent();
String delim = utilJ2C().indents().getDefaultLineDelimiter(document);
if (!body.getImportMemberOrTypes().isEmpty()) {
for (Tree.ImportMemberOrType st:
body.getImportMemberOrTypes()) {
builder.append(indent)
.append(Nodes.text(st, pc.getTokens()))
.append(",")
.append(delim);
}
}
Tree.ImportWildcard wildcard =
body.getImportWildcard();
if (wildcard!=null) {
builder.append(indent)
.append(Nodes.text(wildcard,
pc.getTokens()))
.append(delim);
}
if (builder.toString().endsWith(","+delim)) {
builder.setLength(builder.length()-1-delim.length());
builder.append(delim);
}
if (builder.length()!=0) {
builder.insert(0, delim);
builder.append(bodyIndent);
}
}
else {
return;
}
String text = builder.toString();
int start = bodyNode.getStartIndex()+1;
int end = bodyNode.getEndIndex()-1;
int len = end-start;
try {
if (!document.get(start, len).equals(text)) {
DocumentChange change =
new DocumentChange("Format Block", document);
change.setEdit(new ReplaceEdit(start, len, text));
EditorUtil.performChange(change);
}
}
catch (BadLocationException e) {
e.printStackTrace();
}
}
}