package org.eclipse.dltk.javascript.internal.ui.quickfix;
import org.eclipse.core.resources.IFile;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.ASTVisitor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ISourceRange;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.javascript.ast.BinaryOperation;
import org.eclipse.dltk.javascript.ast.Comment;
import org.eclipse.dltk.javascript.ast.FunctionStatement;
import org.eclipse.dltk.javascript.ast.Identifier;
import org.eclipse.dltk.javascript.ast.JSNode;
import org.eclipse.dltk.javascript.ast.Script;
import org.eclipse.dltk.javascript.ast.Statement;
import org.eclipse.dltk.javascript.internal.ui.JavaScriptUI;
import org.eclipse.dltk.javascript.parser.JavaScriptParserUtil;
import org.eclipse.dltk.ui.DLTKPluginImages;
import org.eclipse.swt.graphics.Image;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
public class CreateLocalVariableQuickFix extends TextFileEditResolution {
public CreateLocalVariableQuickFix(IFile scriptFile, int problemStartIdx) {
super(scriptFile, problemStartIdx);
}
public String getLabel() {
return "Create local variable";
}
@Override
public Image getImage() {
return DLTKPluginImages.getImage(JavaScriptUI.getDefault(),
"icons/obj16/localvariable_obj.gif");
}
public String getDescription() {
Identifier identifier = getIdentifier(getScriptFile(),
getProblemStartIdx());
if (identifier != null) {
ASTNode parent = identifier.getParent();
while (parent instanceof JSNode) {
if (parent instanceof FunctionStatement) {
Statement statement = ((FunctionStatement) parent)
.getBody().getStatements().get(0);
ISourceModule sourceModule = DLTKCore
.createSourceModuleFrom(getScriptFile());
try {
String functionString = sourceModule.getBuffer()
.getText(
parent.sourceStart(),
statement.sourceStart()
- parent.sourceStart());
StringBuilder sb = new StringBuilder(
functionString.length() + 50);
sb.append("<html><body>");
sb.append(functionString.replace("\n", "<br>"));
sb.append("<b>var ");
sb.append(identifier.getName());
sb.append(";</b></body></html>");
return sb.toString();
} catch (ModelException e) {
}
break;
}
parent = ((JSNode) parent).getParent();
}
return "<html><body>Create local variable<br><b>var </b>"
+ identifier.getName() + "<body></html>";
}
return "Failed to create a local variable";
}
@Override
protected MultiTextEdit getTextEdit(IFile file, final int offset) {
MultiTextEdit textEdit = new MultiTextEdit();
final Identifier found = getIdentifier(file, offset);
if (found != null) {
String extraLine = "\n";
ASTNode parent = found.getParent();
ASTNode node = null;
while (parent instanceof JSNode) {
if (parent instanceof FunctionStatement) {
node = ((FunctionStatement) parent).getBody()
.getStatements().get(0);
extraLine = "";
break;
} else if (parent instanceof BinaryOperation
&& ((BinaryOperation) parent).isAssignment()
&& ((BinaryOperation) parent).getLeftExpression() == found) {
textEdit.addChild(new InsertEdit(found.sourceStart(),
"var "));
node = null;
break;
}
parent = ((JSNode) parent).getParent();
if (!(parent instanceof Script))
node = parent;
}
if (node != null) {
Comment documentation = ((JSNode) node).getDocumentation();
String ident = "";
int sourceStart = node.sourceStart();
if (documentation != null)
sourceStart = documentation.sourceStart();
try {
ISourceModule sourceModule = DLTKCore
.createSourceModuleFrom(getScriptFile());
String functionString = sourceModule.getBuffer().getText(
parent.sourceStart(),
sourceStart - parent.sourceStart());
int lastNewLine = functionString.lastIndexOf('\n');
if (lastNewLine != -1)
ident = functionString.substring(lastNewLine);
else
ident = "\n";
} catch (ModelException e) {
}
textEdit.addChild(new InsertEdit(sourceStart, "var "
+ found.getName() + ";" + extraLine + ident));
}
}
return textEdit;
}
/**
* @param file
* @param offset
* @return
*/
public static Identifier getIdentifier(IFile file, final int offset) {
Script script = JavaScriptParserUtil.parse(DLTKCore
.createSourceModuleFrom(file));
final Identifier[] found = new Identifier[1];
ASTVisitor finder = new ASTVisitor() {
@Override
public boolean visitGeneral(ASTNode node) throws Exception {
if (found[0] != null)
return false;
if (node instanceof Identifier) {
ISourceRange range = ((Identifier) node).getRange();
if (range.getOffset() <= offset
&& (range.getOffset() + range.getLength()) >= offset) {
found[0] = (Identifier) node;
return false;
}
}
return true;
}
};
try {
script.traverse(finder);
} catch (Exception e) {
// ignore
e.printStackTrace();
}
return found[0];
}
}