blob: add6f0e5892d9cd8d82e1604fb2a4d28e13f5530 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 ILOG and others.
* 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:
* Joel Cheuoua - Initial API and implementation
*******************************************************************************/
package org.eclipse.jet.internal.editor;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.eval.IEvaluationContext;
import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jet.compiler.CompileOptionsManager;
import org.eclipse.jet.core.compiler.JETCompilerOptions;
import org.eclipse.jet.core.parser.ProblemSeverity;
import org.eclipse.jet.core.parser.ast.JETASTElement;
import org.eclipse.jet.core.parser.ast.JETCompilationUnit;
import org.eclipse.jet.core.parser.ast.JavaDeclaration;
import org.eclipse.jet.core.parser.ast.JavaExpression;
import org.eclipse.jet.core.parser.ast.JavaScriptlet;
import org.eclipse.jet.core.parser.ast.Problem;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IFileEditorInput;
/**
* Helper class for code completion and JET compilation unit processing
* purposespurposes
*
* @author Joel
*
*/
public class JETEditorHelper {
/**
* Problem requestor for java expressions of the JET template
*
* @author Joel
*
*/
private static final class JETJavaContentProblemRequestor implements IProblemRequestor {
/**
* The JET problems computed from the java problems
*/
private List problems;
/**
* The problems collected from the compiled java source
*/
private List javaProblems;
/**
* The jet source
*/
private IDocument jetDocument;
private Map mappingPositions;
private JETJavaContentProblemRequestor(List problems, Map mappings, IDocument jetDocument) {
this.problems = problems;
mappingPositions = mappings;
javaProblems = new ArrayList();
this.jetDocument = jetDocument;
}
/**
* @return
*/
public List getProblems() {
return problems;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.IProblemRequestor#acceptProblem(org.eclipse.
* jdt.core.compiler.IProblem)
*/
public void acceptProblem(IProblem problem) {
javaProblems.add(problem);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.IProblemRequestor#beginReporting()
*/
public void beginReporting() {
javaProblems.clear();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.IProblemRequestor#endReporting()
*/
public void endReporting() {
Problem problem;
// walk through the java problems collected from the generated java
// source and create the
// corresponding JET problems in the JET source using the position
// mappings
for (Iterator iter = javaProblems.iterator(); iter.hasNext();) {
IProblem javaProblem = (IProblem) iter.next();
int javaProblemOffset = javaProblem.getSourceStart();
int problemLength = (javaProblem.getSourceEnd() - javaProblemOffset) + 1;
// Retrieve the corresponding JET AST Element and its position
// in the JET source
JETASTElement astElement = getElementForJavaOffset(javaProblemOffset);
Position pos = (Position) mappingPositions.get(astElement);
// jetOffset =
// start position of the AST element in JET Code +
// offset till the position delimited by the javaProblemOffset
// The offset till the position delimited by the
// javaProblemOffset
// depends on the starting offset of the java content in the JET
// AST element.
// This is due to the fact that the JET AST element first
// position does not represents the starting offset of
// offset of its java content.
int astElementJavaContentStart = pos == null ? -1 : pos.getOffset();
int jetOffset = pos == null ? 0 : JETEditorHelper.getASTElementContentStart(astElement, jetDocument) + (javaProblemOffset - astElementJavaContentStart);
// Create the problem at the specified location
URI baseLocation = URI.create("");
problem = new Problem(baseLocation, "", javaProblem.isWarning() ? ProblemSeverity.WARNING : ProblemSeverity.ERROR, -1, javaProblem.getMessage(), javaProblem.getArguments(), jetOffset, jetOffset + problemLength, -1, -1);
// add the problem to the problems list
problems.add(problem);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.IProblemRequestor#isActive()
*/
public boolean isActive() {
return true;
}
/**
* Find the JET AST element that matches the given java offset in the
* generated java template source
*
* @param javaOffset
* @return
*/
private JETASTElement getElementForJavaOffset(int javaOffset) {
for (Iterator iterator = mappingPositions.keySet().iterator(); iterator.hasNext();) {
JETASTElement element = (JETASTElement) iterator.next();
Position pos = (Position) mappingPositions.get(element);
if (pos.getOffset() <= javaOffset && javaOffset < pos.getOffset() + pos.getLength())
return element;
}
return null;
}
} // End class JETJavaContentProblemRequestor
/**
* @param astElement
* @param jetDocument
* @return
*/
public static int getASTElementContentStart(JETASTElement astElement, IDocument jetDocument) {
int jetStart = astElement.getStart();
if (astElement instanceof JavaDeclaration)
jetStart += 3;
if ((astElement instanceof JavaExpression) || (astElement instanceof JavaScriptlet))
try {
String jetSnippet = jetDocument.get(jetStart, astElement.getEnd() - jetStart);
String javaContent = (astElement instanceof JavaExpression) ? ((JavaExpression) astElement).getJavaContent() : ((JavaScriptlet) astElement).getJavaContent();
int idx = jetSnippet.indexOf(javaContent);
jetStart += idx;
} catch (BadLocationException e) {
Activator.log(e);
}
return jetStart;
}
public static boolean checkOffsetPositions(String javaSource, String jetSource, int jetOffset, int javaOffset, int checkDepth) {
boolean result = false;
String javaCheckString = javaSource.substring(javaOffset, Math.min(javaSource.length(), javaOffset + checkDepth));
String jetCheckString = jetSource.substring(jetOffset, Math.min(jetSource.length(), jetOffset + checkDepth));
result = javaCheckString.compareTo(jetCheckString) == 0;
if (!result) {
System.err.println("position matching error");
System.err.println("JET Check String : " + jetCheckString);
System.err.println("Java Check String : " + javaCheckString);
}
return result;
}
/**
* @param jetEditor
* @param cu
* @param jetDocument
* @return
*/
public static List evaluateProblems(JETTextEditor jetEditor, IDocument jetDocument) {
JETCompilationUnit cu = jetEditor.requestCompilationUnit();
String packageName = cu.getOutputJavaPackage();
String className = cu.getOutputJavaClassName();
List problems = new ArrayList();
if (packageName == null || className == null)
return problems;
Map mappingPositions = new HashMap();
String javaSource = jetEditor.compilationHelper().getJavaCode(cu, mappingPositions);
JETJavaContentProblemRequestor problemRequestor = new JETJavaContentProblemRequestor(problems, mappingPositions, jetDocument);
try {
ICompilationUnit compilationUnit = null;
IJavaProject javaProject = jetEditor.getJavaProject();
System.out.println("Project: " + javaProject.getElementName());
if (!javaProject.getElementName().startsWith("."))
System.out.println();
IPackageFragmentRoot roots[] = javaProject.getPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
IPackageFragmentRoot root = roots[i];
if (IPackageFragmentRoot.K_SOURCE != root.getKind()) {
continue;
}
IPackageFragment packageFragment = root.getPackageFragment(packageName);
if (packageFragment == null || !packageFragment.exists())
packageFragment = root.createPackageFragment(packageName, true, new NullProgressMonitor());
compilationUnit = packageFragment.createCompilationUnit((new StringBuilder(String.valueOf(className))).append(".java").toString(), javaSource, true, new NullProgressMonitor());
break;
}
WorkingCopyOwner owner = new WorkingCopyOwner() {
};
ICompilationUnit copy = compilationUnit.getWorkingCopy(owner, problemRequestor, null);
copy.reconcile(0, true, owner, null);
} catch (JavaModelException e) {
System.out.println(e);
Activator.log(e);
}
return problems;
}
/**
* @param javaProject
* @param cu
* @param codeSnippet
* @param offset
* @return
*/
public static CompletionProposalCollector collect(IJavaProject javaProject, JETCompilationUnit cu, String codeSnippet, int offset) {
IEvaluationContext context;
CompletionProposalCollector proposalCollector;
context = javaProject.newEvaluationContext();
List importList = new ArrayList();
importList.addAll(cu.getImports());
importList.add("org.eclipse.jet.JET2Context");
importList.add("org.eclipse.jet.JET2Template");
importList.add("org.eclipse.jet.JET2Writer");
importList.add("org.eclipse.jet.taglib.RuntimeTagElement");
importList.add("org.eclipse.jet.taglib.TagInfo");
String imports[] = new String[importList.size()];
importList.toArray(imports);
String packageName = cu.getOutputJavaPackage();
if (packageName == null) {
Map options = CompileOptionsManager.getOptions(javaProject.getProject());
if (options.isEmpty())
options = JETCompilerOptions.getDefaultCompilerOptions();
packageName = (String) options.get("org.eclipse.jet.compiledTemplatePackage");
}
context.setPackageName(packageName);
context.setImports(imports);
proposalCollector = new CompletionProposalCollector(javaProject);
try {
context.codeComplete(codeSnippet, offset, proposalCollector);
return proposalCollector;
} catch (JavaModelException e) {
Activator.log(e);
}
return null;
}
/**
* @param editor
* @param viewer
* @param completionOffset
* @return
*/
public static IJavaCompletionProposal[] getJavaCompletionProposal(JETTextEditor jetEditor, ITextViewer viewer, int completionOffset) {
IJavaProject javaProject;
String packageName;
String className;
Map mappingPositions;
IDocument javaDocument;
JETCompilationUnit cu = jetEditor.requestCompilationUnit();
javaProject = jetEditor.getJavaProject();
packageName = cu.getOutputJavaPackage();
className = cu.getOutputJavaClassName();
if (packageName == null) {
Map options = CompileOptionsManager.getOptions(javaProject.getProject());
if (options.isEmpty())
options = JETCompilerOptions.getDefaultCompilerOptions();
packageName = (String) options.get("org.eclipse.jet.compiledTemplatePackage");
}
if (className == null && (jetEditor.getEditorInput() instanceof IFileEditorInput)) {
IFile file = ((IFileEditorInput) jetEditor.getEditorInput()).getFile();
String inputName = file.getFullPath().removeFileExtension().lastSegment();
String baseClassName = makeJavaClassName(inputName);
className = baseClassName;
}
if (packageName == null || className == null)
return new IJavaCompletionProposal[0];
mappingPositions = new HashMap();
javaDocument = new Document(jetEditor.compilationHelper().getJavaCode(cu, mappingPositions));
IJavaCompletionProposal results[];
ICompilationUnit compilationUnit = null;
try {
IPackageFragmentRoot roots[] = javaProject.getPackageFragmentRoots();
for (int i = 0; i < roots.length;) {
IPackageFragmentRoot root = roots[i];
IPackageFragment packageFragment = root.getPackageFragment(packageName);
if (packageFragment == null || !packageFragment.exists())
packageFragment = root.createPackageFragment(packageName, true, new NullProgressMonitor());
compilationUnit = packageFragment.createCompilationUnit((new StringBuilder(String.valueOf(className))).append(".java").toString(), javaDocument.get(), true, new NullProgressMonitor());
break;
}
CompletionProposalCollector proposalCollector = new CompletionProposalCollector(compilationUnit);
JETASTElement astElement = jetEditor.getASTElement(completionOffset);
Position javaPosition = (Position) mappingPositions.get(astElement);
int jetStart = getASTElementContentStart(astElement, viewer.getDocument());
int javaStart = javaPosition.getOffset();
int javaCompletionOffset = javaStart + (completionOffset - jetStart);
compilationUnit.codeComplete(javaCompletionOffset, proposalCollector);
Point selection = viewer.getSelectedRange();
if (selection.y > 0)
proposalCollector.setReplacementLength(selection.y);
IJavaCompletionProposal javaProposals[] = proposalCollector.getJavaCompletionProposals();
IJavaCompletionProposal keywordsProposals[] = proposalCollector.getKeywordCompletionProposals();
IJavaCompletionProposal unsortedJavaProposals[] = new IJavaCompletionProposal[javaProposals.length + keywordsProposals.length];
System.arraycopy(keywordsProposals, 0, unsortedJavaProposals, 0, keywordsProposals.length);
System.arraycopy(javaProposals, 0, unsortedJavaProposals, keywordsProposals.length, javaProposals.length);
List sortedJavaProposals = new LinkedList();
for (int i = 0; i < unsortedJavaProposals.length; i++) {
IJavaCompletionProposal unsortedJavaProposal = unsortedJavaProposals[i];
int index = 0;
for (Iterator iterator = sortedJavaProposals.iterator(); iterator.hasNext();) {
IJavaCompletionProposal proposal = (IJavaCompletionProposal) iterator.next();
if (proposal.getRelevance() <= unsortedJavaProposal.getRelevance()) {
index = sortedJavaProposals.indexOf(proposal);
break;
}
}
sortedJavaProposals.add(index, unsortedJavaProposal);
}
results = new IJavaCompletionProposal[sortedJavaProposals.size()];
sortedJavaProposals.toArray(results);
adjustResults(results, completionOffset);
return results;
} catch (JavaModelException e) {
Activator.log(e);
}
return new IJavaCompletionProposal[0];
}
/**
* @param javaProject
* @param cu
* @param codeSnippet
* @param viewer
* @param offset
* @return
*/
public static IJavaCompletionProposal[] getJavaCompletionProposal(IJavaProject javaProject, JETCompilationUnit cu, String codeSnippet, ITextViewer viewer, int offset) {
CompletionProposalCollector proposalCollector = collect(javaProject, cu, codeSnippet, offset);
if (proposalCollector != null) {
Point selection = viewer.getSelectedRange();
if (selection.y > 0)
proposalCollector.setReplacementLength(selection.y);
IJavaCompletionProposal javaProposals[] = proposalCollector.getJavaCompletionProposals();
IJavaCompletionProposal keywordsProposals[] = proposalCollector.getKeywordCompletionProposals();
IJavaCompletionProposal unsortedJavaProposals[] = new IJavaCompletionProposal[javaProposals.length + keywordsProposals.length];
System.arraycopy(keywordsProposals, 0, unsortedJavaProposals, 0, keywordsProposals.length);
System.arraycopy(javaProposals, 0, unsortedJavaProposals, keywordsProposals.length, javaProposals.length);
List sortedJavaProposals = new LinkedList();
for (int i = 0; i < unsortedJavaProposals.length; i++) {
IJavaCompletionProposal unsortedJavaProposal = unsortedJavaProposals[i];
int index = 0;
for (Iterator iterator = sortedJavaProposals.iterator(); iterator.hasNext();) {
IJavaCompletionProposal proposal = (IJavaCompletionProposal) iterator.next();
if (proposal.getRelevance() <= unsortedJavaProposal.getRelevance()) {
index = sortedJavaProposals.indexOf(proposal);
break;
}
}
sortedJavaProposals.add(index, unsortedJavaProposal);
}
IJavaCompletionProposal results[] = new IJavaCompletionProposal[sortedJavaProposals.size()];
sortedJavaProposals.toArray(results);
return results;
} else {
return new IJavaCompletionProposal[0];
}
}
/**
* @param results
* @param offset
*/
public static void adjustResults(IJavaCompletionProposal[] results, int offset) {
for (int i = 0; i < results.length; i++)
if (results[i] instanceof AbstractJavaCompletionProposal) {
AbstractJavaCompletionProposal proposal = (AbstractJavaCompletionProposal) results[i];
proposal.setReplacementOffset(offset);
}
}
/**
* @param results
* @param offset
* @param allWords
*/
public static void adjustJavaScriptletProposalResults(IJavaCompletionProposal[] results, int offset) {
if (results.length > 0) {
IJavaCompletionProposal iJavaCompletionProposal = results[0];
if (iJavaCompletionProposal instanceof AbstractJavaCompletionProposal) {
AbstractJavaCompletionProposal proposal = (AbstractJavaCompletionProposal) iJavaCompletionProposal;
int replacementLength = proposal.getReplacementLength();
adjustResults(results, offset - replacementLength);
}
}
}
/**
* @param name
* @return
*/
public static String makeJavaClassName(String name) {
StringBuffer result = new StringBuffer("_jet_");
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (Character.isJavaIdentifierPart(c))
result.append(c);
}
return result.toString();
}
}