1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.corext.template.php;
13 import java.lang.reflect.InvocationTargetException;
15 import net.sourceforge.phpdt.core.ICompilationUnit;
16 import net.sourceforge.phpdt.internal.corext.Assert;
17 import net.sourceforge.phpdt.internal.corext.template.php.CompilationUnitCompletion.LocalVariable;
18 import net.sourceforge.phpdt.internal.corext.util.Strings;
19 import net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage;
20 import net.sourceforge.phpdt.internal.ui.text.template.contentassist.MultiVariable;
21 import net.sourceforge.phpdt.internal.ui.util.ExceptionHandler;
22 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.jface.dialogs.MessageDialog;
28 import org.eclipse.jface.preference.IPreferenceStore;
29 import org.eclipse.jface.text.BadLocationException;
30 import org.eclipse.jface.text.Document;
31 import org.eclipse.jface.text.IDocument;
32 import org.eclipse.jface.text.IRegion;
33 import org.eclipse.jface.text.templates.Template;
34 import org.eclipse.jface.text.templates.TemplateBuffer;
35 import org.eclipse.jface.text.templates.TemplateContextType;
36 import org.eclipse.jface.text.templates.TemplateException;
37 import org.eclipse.jface.text.templates.TemplateTranslator;
38 import org.eclipse.jface.text.templates.TemplateVariable;
39 import org.eclipse.swt.widgets.Shell;
42 * A context for java source.
44 public class JavaContext extends CompilationUnitContext {
46 /** The platform default line delimiter. */
47 private static final String PLATFORM_LINE_DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$
49 /** A code completion requestor for guessing local variable names. */
50 private CompilationUnitCompletion fCompletion;
53 * Creates a java template context.
59 * @param completionOffset
60 * the completion offset within the document.
61 * @param completionLength
62 * the completion length.
63 * @param compilationUnit
64 * the compilation unit (may be <code>null</code>).
66 public JavaContext(TemplateContextType type, IDocument document, int completionOffset, int completionLength,
67 ICompilationUnit compilationUnit) {
68 super(type, document, completionOffset, completionLength, compilationUnit);
72 * Returns the indentation level at the position of code completion.
74 private int getIndentation() {
75 int start = getStart();
76 IDocument document = getDocument();
78 IRegion region = document.getLineInformationOfOffset(start);
79 String lineContent = document.get(region.getOffset(), region.getLength());
80 return Strings.computeIndent(lineContent, CodeFormatterPreferencePage.getTabSize());
81 // return Strings.computeIndent(lineContent, CodeFormatterUtil.getTabWidth());
82 } catch (BadLocationException e) {
88 * @see TemplateContext#evaluate(Template template)
90 public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
92 if (!canEvaluate(template))
93 throw new TemplateException(JavaTemplateMessages.getString("Context.error.cannot.evaluate")); //$NON-NLS-1$
95 TemplateTranslator translator = new TemplateTranslator() {
97 * @see org.eclipse.jface.text.templates.TemplateTranslator#createVariable(java.lang.String, java.lang.String, int[])
99 protected TemplateVariable createVariable(String type, String name, int[] offsets) {
100 return new MultiVariable(type, name, offsets);
103 TemplateBuffer buffer = translator.translate(template);
105 getContextType().resolve(buffer, this);
106 String lineDelimiter = null;
108 lineDelimiter = getDocument().getLineDelimiter(0);
109 } catch (BadLocationException e) {
112 if (lineDelimiter == null)
113 lineDelimiter = PLATFORM_LINE_DELIMITER;
114 IPreferenceStore prefs = PHPeclipsePlugin.getDefault().getPreferenceStore();
116 // boolean useCodeFormatter = prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
117 boolean useCodeFormatter = false;
120 JavaFormatter formatter = new JavaFormatter(lineDelimiter, getIndentation(), useCodeFormatter);
121 formatter.format(buffer, this);
123 // String res = buffer.getString();
124 // res = res.replaceAll("\n","/n");
125 // res = res.replaceAll("\t","/t");
126 // System.out.println(res);
132 * @see TemplateContext#canEvaluate(Template templates)
134 public boolean canEvaluate(Template template) {
135 String key = getKey();
137 if (fForceEvaluation)
140 return template.matches(key, getContextType().getId()) && key.length() != 0
141 && template.getName().toLowerCase().startsWith(key.toLowerCase());
144 public boolean canEvaluate(String identifier) {
145 String prefix = getKey();
146 return identifier.toLowerCase().startsWith(prefix.toLowerCase());
150 * @see DocumentTemplateContext#getCompletionPosition();
152 public int getStart() {
155 IDocument document = getDocument();
157 if (getCompletionLength() == 0) {
159 int start = getCompletionOffset();
160 while ((start != 0) && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
163 if ((start != 0) && (Character.isUnicodeIdentifierStart(document.getChar(start - 1))||(document.getChar(start - 1)=='$') ))
170 int start = getCompletionOffset();
171 int end = getCompletionOffset() + getCompletionLength();
173 while (start != 0 && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
175 if ((start != 0) && (Character.isUnicodeIdentifierStart(document.getChar(start - 1))||(document.getChar(start - 1)=='$') ))
177 while (start != end && Character.isWhitespace(document.getChar(start)))
181 start = getCompletionOffset();
186 } catch (BadLocationException e) {
187 return super.getStart();
192 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getEnd()
194 public int getEnd() {
196 if (getCompletionLength() == 0)
197 return super.getEnd();
200 IDocument document = getDocument();
202 int start = getCompletionOffset();
203 int end = getCompletionOffset() + getCompletionLength();
205 while (start != end && Character.isWhitespace(document.getChar(end - 1)))
210 } catch (BadLocationException e) {
211 return super.getEnd();
216 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getKey()
218 public String getKey() {
220 // if (getCompletionLength() == 0) {
221 // return super.getKey();
225 IDocument document = getDocument();
227 int start = getStart();
228 int end = getCompletionOffset();
229 return start <= end ? document.get(start, end - start) : ""; //$NON-NLS-1$
231 } catch (BadLocationException e) {
232 return super.getKey();
237 * Returns the character before start position of completion.
239 public char getCharacterBeforeStart() {
240 int start = getStart();
243 return start == 0 ? ' ' : getDocument().getChar(start - 1);
245 } catch (BadLocationException e) {
250 private static void handleException(Shell shell, Exception e) {
251 String title = JavaTemplateMessages.getString("JavaContext.error.title"); //$NON-NLS-1$
252 if (e instanceof CoreException)
253 ExceptionHandler.handle((CoreException) e, shell, title, null);
254 else if (e instanceof InvocationTargetException)
255 ExceptionHandler.handle((InvocationTargetException) e, shell, title, null);
257 PHPeclipsePlugin.log(e);
258 MessageDialog.openError(shell, title, e.getMessage());
262 // private CompilationUnitCompletion getCompletion() {
263 // ICompilationUnit compilationUnit= getCompilationUnit();
264 // if (fCompletion == null) {
265 // fCompletion= new CompilationUnitCompletion(compilationUnit);
267 // if (compilationUnit != null) {
269 // compilationUnit.codeComplete(getStart(), fCompletion);
270 // } catch (JavaModelException e) {
276 // return fCompletion;
280 * Returns the name of a guessed local array, <code>null</code> if no local array exists.
282 // public String guessArray() {
283 // return firstOrNull(guessArrays());
286 * Returns the name of a guessed local array, <code>null</code> if no local array exists.
288 // public String[] guessArrays() {
289 // CompilationUnitCompletion completion= getCompletion();
290 // LocalVariable[] localArrays= completion.findLocalArrays();
292 // String[] ret= new String[localArrays.length];
293 // for (int i= 0; i < ret.length; i++) {
294 // ret[ret.length - i - 1]= localArrays[i].name;
299 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
301 // public String guessArrayType() {
302 // return firstOrNull(guessArrayTypes());
304 private String firstOrNull(String[] strings) {
305 if (strings.length > 0)
312 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
314 // public String[][] guessGroupedArrayTypes() {
315 // CompilationUnitCompletion completion= getCompletion();
316 // LocalVariable[] localArrays= completion.findLocalArrays();
318 // String[][] ret= new String[localArrays.length][];
320 // for (int i= 0; i < localArrays.length; i++) {
321 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
322 // ret[i]= new String[] {type};
328 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
330 // public String[] guessArrayTypes() {
331 // CompilationUnitCompletion completion= getCompletion();
332 // LocalVariable[] localArrays= completion.findLocalArrays();
334 // List ret= new ArrayList();
336 // for (int i= 0; i < localArrays.length; i++) {
337 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
338 // if (!ret.contains(type))
342 // return (String[]) ret.toArray(new String[ret.size()]);
344 private String getArrayTypeFromLocalArray(CompilationUnitCompletion completion, LocalVariable array) {
345 String arrayTypeName = array.typeName;
346 String typeName = getScalarType(arrayTypeName);
347 int dimension = getArrayDimension(arrayTypeName) - 1;
348 Assert.isTrue(dimension >= 0);
350 String qualifiedName = createQualifiedTypeName(array.typePackageName, typeName);
351 String innerTypeName = completion.simplifyTypeName(qualifiedName);
353 return innerTypeName == null ? createArray(typeName, dimension) : createArray(innerTypeName, dimension);
356 private static String createArray(String type, int dimension) {
357 StringBuffer buffer = new StringBuffer(type);
358 for (int i = 0; i < dimension; i++)
359 buffer.append("[]"); //$NON-NLS-1$
360 return buffer.toString();
363 private static String getScalarType(String type) {
364 return type.substring(0, type.indexOf('['));
367 private static int getArrayDimension(String type) {
370 int index = type.indexOf('[');
372 while (index != -1) {
374 index = type.indexOf('[', index + 1);
380 private static String createQualifiedTypeName(String packageName, String className) {
381 StringBuffer buffer = new StringBuffer();
383 if (packageName.length() != 0) {
384 buffer.append(packageName);
387 buffer.append(className);
389 return buffer.toString();
393 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
395 // public String guessArrayElement() {
396 // return firstOrNull(guessArrayElements());
399 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
401 // public String[] guessArrayElements() {
402 // ICompilationUnit cu= getCompilationUnit();
404 // return new String[0];
407 // CompilationUnitCompletion completion= getCompletion();
408 // LocalVariable[] localArrays= completion.findLocalArrays();
410 // List ret= new ArrayList();
412 // for (int i= 0; i < localArrays.length; i++) {
413 // int idx= localArrays.length - i - 1;
415 // LocalVariable var= localArrays[idx];
417 // IJavaProject project= cu.getJavaProject();
418 // String typeName= var.typeName;
419 // String baseTypeName= typeName.substring(0, typeName.lastIndexOf('['));
421 // String indexName= getIndex();
422 // String[] excludedNames= completion.getLocalVariableNames();
423 // if (indexName != null) {
424 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
425 // excludedNamesList.add(indexName);
426 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
428 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, baseTypeName, 0, excludedNames);
429 // for (int j= 0; j < proposals.length; j++) {
430 // if (!ret.contains(proposals[j]))
431 // ret.add(proposals[j]);
435 // return (String[]) ret.toArray(new String[ret.size()]);
438 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
440 // public String[][] guessGroupedArrayElements() {
441 // ICompilationUnit cu= getCompilationUnit();
443 // return new String[0][];
446 // CompilationUnitCompletion completion= getCompletion();
447 // LocalVariable[] localArrays= completion.findLocalArrays();
449 // String[][] ret= new String[localArrays.length][];
451 // for (int i= 0; i < localArrays.length; i++) {
452 // int idx= localArrays.length - i - 1;
454 // LocalVariable var= localArrays[idx];
456 // IJavaProject project= cu.getJavaProject();
457 // String typeName= var.typeName;
458 // int dim= -1; // we expect at least one array
459 // int lastIndex= typeName.length();
460 // int bracket= typeName.lastIndexOf('[');
461 // while (bracket != -1) {
462 // lastIndex= bracket;
464 // bracket= typeName.lastIndexOf('[', bracket - 1);
466 // typeName= typeName.substring(0, lastIndex);
468 // String indexName= getIndex();
469 // String[] excludedNames= completion.getLocalVariableNames();
470 // if (indexName != null) {
471 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
472 // excludedNamesList.add(indexName);
473 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
475 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, typeName, dim, excludedNames);
477 // ret[i]= proposals;
483 * Returns an array index name. 'i', 'j', 'k' are tried until no name collision with an existing local variable occurs. If all
484 * names collide, <code>null</code> is returned.
486 // public String getIndex() {
487 // CompilationUnitCompletion completion= getCompletion();
488 // String[] proposals= {"i", "j", "k"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
490 // for (int i= 0; i != proposals.length; i++) {
491 // String proposal = proposals[i];
493 // if (!completion.existsLocalName(proposal))
500 * Returns the name of a local collection, <code>null</code> if no local collection exists.
502 // public String guessCollection() {
503 // return firstOrNull(guessCollections());
506 * Returns the names of local collections.
508 // public String[] guessCollections() {
509 // CompilationUnitCompletion completion= getCompletion();
511 // LocalVariable[] localCollections= completion.findLocalCollections();
512 // String[] ret= new String[localCollections.length];
513 // for (int i= 0; i < ret.length; i++) {
514 // ret[ret.length - i - 1]= localCollections[i].name;
519 // } catch (JavaModelException e) {
520 // JavaPlugin.log(e);
523 // return new String[0];
526 * Returns an iterator name ('iter'). If 'iter' already exists as local variable, <code>null</code> is returned.
528 // public String getIterator() {
529 // CompilationUnitCompletion completion= getCompletion();
530 // String[] proposals= {"iter"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
532 // for (int i= 0; i != proposals.length; i++) {
533 // String proposal = proposals[i];
535 // if (!completion.existsLocalName(proposal))
541 // public void addIteratorImport() {
542 // ICompilationUnit cu= getCompilationUnit();
548 // Position position= new Position(getCompletionOffset(), getCompletionLength());
549 // IDocument document= getDocument();
550 // final String category= "__template_position_importer" + System.currentTimeMillis(); //$NON-NLS-1$
551 // IPositionUpdater updater= new DefaultPositionUpdater(category);
552 // document.addPositionCategory(category);
553 // document.addPositionUpdater(updater);
554 // document.addPosition(position);
556 // CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings();
557 // ImportsStructure structure= new ImportsStructure(cu, settings.importOrder, settings.importThreshold, true);
558 // structure.addImport("java.util.Iterator"); //$NON-NLS-1$
559 // structure.create(false, null);
561 // document.removePosition(position);
562 // document.removePositionUpdater(updater);
563 // document.removePositionCategory(category);
565 // setCompletionOffset(position.getOffset());
566 // setCompletionLength(position.getLength());
568 // } catch (CoreException e) {
569 // handleException(null, e);
570 // } catch (BadLocationException e) {
571 // handleException(null, e);
572 // } catch (BadPositionCategoryException e) {
573 // handleException(null, e);
577 * Evaluates a 'java' template in thecontext of a compilation unit
579 public static String evaluateTemplate(Template template, ICompilationUnit compilationUnit, int position) throws CoreException,
580 BadLocationException, TemplateException {
582 TemplateContextType contextType = PHPeclipsePlugin.getDefault().getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
583 if (contextType == null)
584 throw new CoreException(new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.ERROR, JavaTemplateMessages
585 .getString("JavaContext.error.message"), null)); //$NON-NLS-1$
587 IDocument document = new Document();
588 if (compilationUnit != null && compilationUnit.exists())
589 document.set(compilationUnit.getSource());
591 JavaContext context = new JavaContext(contextType, document, position, 0, compilationUnit);
592 context.setForceEvaluation(true);
594 TemplateBuffer buffer = context.evaluate(template);
597 return buffer.getString();