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
48 .getProperty("line.separator"); //$NON-NLS-1$
50 /** A code completion requestor for guessing local variable names. */
51 private CompilationUnitCompletion fCompletion;
54 * Creates a java template context.
60 * @param completionOffset
61 * the completion offset within the document.
62 * @param completionLength
63 * the completion length.
64 * @param compilationUnit
65 * the compilation unit (may be <code>null</code>).
67 public JavaContext(TemplateContextType type, IDocument document,
68 int completionOffset, int completionLength,
69 ICompilationUnit compilationUnit) {
70 super(type, document, completionOffset, completionLength,
75 * Returns the indentation level at the position of code completion.
77 private int getIndentation() {
78 int start = getStart();
79 IDocument document = getDocument();
81 IRegion region = document.getLineInformationOfOffset(start);
82 String lineContent = document.get(region.getOffset(), region
84 return Strings.computeIndent(lineContent,
85 CodeFormatterPreferencePage.getTabSize());
86 // return Strings.computeIndent(lineContent,
87 // CodeFormatterUtil.getTabWidth());
88 } catch (BadLocationException e) {
94 * @see TemplateContext#evaluate(Template template)
96 public TemplateBuffer evaluate(Template template)
97 throws BadLocationException, TemplateException {
99 if (!canEvaluate(template))
100 throw new TemplateException(JavaTemplateMessages
101 .getString("Context.error.cannot.evaluate")); //$NON-NLS-1$
103 TemplateTranslator translator = new TemplateTranslator() {
105 * @see org.eclipse.jface.text.templates.TemplateTranslator#createVariable(java.lang.String,
106 * java.lang.String, int[])
108 protected TemplateVariable createVariable(String type, String name,
110 return new MultiVariable(type, name, offsets);
113 TemplateBuffer buffer = translator.translate(template);
115 getContextType().resolve(buffer, this);
116 String lineDelimiter = null;
118 lineDelimiter = getDocument().getLineDelimiter(0);
119 } catch (BadLocationException e) {
122 if (lineDelimiter == null)
123 lineDelimiter = PLATFORM_LINE_DELIMITER;
124 IPreferenceStore prefs = PHPeclipsePlugin.getDefault()
125 .getPreferenceStore();
127 // boolean useCodeFormatter =
128 // prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
129 boolean useCodeFormatter = false;
132 JavaFormatter formatter = new JavaFormatter(lineDelimiter,
133 getIndentation(), useCodeFormatter);
134 formatter.format(buffer, this);
136 // String res = buffer.getString();
137 // res = res.replaceAll("\n","/n");
138 // res = res.replaceAll("\t","/t");
139 // System.out.println(res);
145 * @see TemplateContext#canEvaluate(Template templates)
147 public boolean canEvaluate(Template template) {
148 String key = getKey();
150 if (fForceEvaluation)
153 return template.matches(key, getContextType().getId())
155 && template.getName().toLowerCase().startsWith(
159 public boolean canEvaluate(String identifier) {
160 String prefix = getKey();
161 return identifier.toLowerCase().startsWith(prefix.toLowerCase());
165 * @see DocumentTemplateContext#getCompletionPosition();
167 public int getStart() {
170 IDocument document = getDocument();
172 if (getCompletionLength() == 0) {
174 int start = getCompletionOffset();
176 && Character.isUnicodeIdentifierPart(document
177 .getChar(start - 1)))
181 && (Character.isUnicodeIdentifierStart(document
182 .getChar(start - 1)) || (document
183 .getChar(start - 1) == '$')))
190 int start = getCompletionOffset();
191 int end = getCompletionOffset() + getCompletionLength();
194 && Character.isUnicodeIdentifierPart(document
195 .getChar(start - 1)))
198 && (Character.isUnicodeIdentifierStart(document
199 .getChar(start - 1)) || (document
200 .getChar(start - 1) == '$')))
203 && Character.isWhitespace(document.getChar(start)))
207 start = getCompletionOffset();
212 } catch (BadLocationException e) {
213 return super.getStart();
218 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getEnd()
220 public int getEnd() {
222 if (getCompletionLength() == 0)
223 return super.getEnd();
226 IDocument document = getDocument();
228 int start = getCompletionOffset();
229 int end = getCompletionOffset() + getCompletionLength();
232 && Character.isWhitespace(document.getChar(end - 1)))
237 } catch (BadLocationException e) {
238 return super.getEnd();
243 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getKey()
245 public String getKey() {
247 // if (getCompletionLength() == 0) {
248 // return super.getKey();
252 IDocument document = getDocument();
254 int start = getStart();
255 int end = getCompletionOffset();
256 return start <= end ? document.get(start, end - start) : ""; //$NON-NLS-1$
258 } catch (BadLocationException e) {
259 return super.getKey();
264 * Returns the character before start position of completion.
266 public char getCharacterBeforeStart() {
267 int start = getStart();
270 return start == 0 ? ' ' : getDocument().getChar(start - 1);
272 } catch (BadLocationException e) {
277 private static void handleException(Shell shell, Exception e) {
278 String title = JavaTemplateMessages
279 .getString("JavaContext.error.title"); //$NON-NLS-1$
280 if (e instanceof CoreException)
281 ExceptionHandler.handle((CoreException) e, shell, title, null);
282 else if (e instanceof InvocationTargetException)
283 ExceptionHandler.handle((InvocationTargetException) e, shell,
286 PHPeclipsePlugin.log(e);
287 MessageDialog.openError(shell, title, e.getMessage());
291 // private CompilationUnitCompletion getCompletion() {
292 // ICompilationUnit compilationUnit= getCompilationUnit();
293 // if (fCompletion == null) {
294 // fCompletion= new CompilationUnitCompletion(compilationUnit);
296 // if (compilationUnit != null) {
298 // compilationUnit.codeComplete(getStart(), fCompletion);
299 // } catch (JavaModelException e) {
305 // return fCompletion;
309 * Returns the name of a guessed local array, <code>null</code> if no
310 * local array exists.
312 // public String guessArray() {
313 // return firstOrNull(guessArrays());
316 * Returns the name of a guessed local array, <code>null</code> if no
317 * local array exists.
319 // public String[] guessArrays() {
320 // CompilationUnitCompletion completion= getCompletion();
321 // LocalVariable[] localArrays= completion.findLocalArrays();
323 // String[] ret= new String[localArrays.length];
324 // for (int i= 0; i < ret.length; i++) {
325 // ret[ret.length - i - 1]= localArrays[i].name;
330 * Returns the name of the type of a local array, <code>null</code> if no
331 * local array exists.
333 // public String guessArrayType() {
334 // return firstOrNull(guessArrayTypes());
336 private String firstOrNull(String[] strings) {
337 if (strings.length > 0)
344 * Returns the name of the type of a local array, <code>null</code> if no
345 * local array exists.
347 // public String[][] guessGroupedArrayTypes() {
348 // CompilationUnitCompletion completion= getCompletion();
349 // LocalVariable[] localArrays= completion.findLocalArrays();
351 // String[][] ret= new String[localArrays.length][];
353 // for (int i= 0; i < localArrays.length; i++) {
354 // String type= getArrayTypeFromLocalArray(completion,
355 // localArrays[localArrays.length - i - 1]);
356 // ret[i]= new String[] {type};
362 * Returns the name of the type of a local array, <code>null</code> if no
363 * local array exists.
365 // public String[] guessArrayTypes() {
366 // CompilationUnitCompletion completion= getCompletion();
367 // LocalVariable[] localArrays= completion.findLocalArrays();
369 // List ret= new ArrayList();
371 // for (int i= 0; i < localArrays.length; i++) {
372 // String type= getArrayTypeFromLocalArray(completion,
373 // localArrays[localArrays.length - i - 1]);
374 // if (!ret.contains(type))
378 // return (String[]) ret.toArray(new String[ret.size()]);
380 private String getArrayTypeFromLocalArray(
381 CompilationUnitCompletion completion, LocalVariable array) {
382 String arrayTypeName = array.typeName;
383 String typeName = getScalarType(arrayTypeName);
384 int dimension = getArrayDimension(arrayTypeName) - 1;
385 Assert.isTrue(dimension >= 0);
387 String qualifiedName = createQualifiedTypeName(array.typePackageName,
389 String innerTypeName = completion.simplifyTypeName(qualifiedName);
391 return innerTypeName == null ? createArray(typeName, dimension)
392 : createArray(innerTypeName, dimension);
395 private static String createArray(String type, int dimension) {
396 StringBuffer buffer = new StringBuffer(type);
397 for (int i = 0; i < dimension; i++)
398 buffer.append("[]"); //$NON-NLS-1$
399 return buffer.toString();
402 private static String getScalarType(String type) {
403 return type.substring(0, type.indexOf('['));
406 private static int getArrayDimension(String type) {
409 int index = type.indexOf('[');
411 while (index != -1) {
413 index = type.indexOf('[', index + 1);
419 private static String createQualifiedTypeName(String packageName,
421 StringBuffer buffer = new StringBuffer();
423 if (packageName.length() != 0) {
424 buffer.append(packageName);
427 buffer.append(className);
429 return buffer.toString();
433 * Returns a proposal for a variable name of a local array element,
434 * <code>null</code> if no local array exists.
436 // public String guessArrayElement() {
437 // return firstOrNull(guessArrayElements());
440 * Returns a proposal for a variable name of a local array element,
441 * <code>null</code> if no local array exists.
443 // public String[] guessArrayElements() {
444 // ICompilationUnit cu= getCompilationUnit();
446 // return new String[0];
449 // CompilationUnitCompletion completion= getCompletion();
450 // LocalVariable[] localArrays= completion.findLocalArrays();
452 // List ret= new ArrayList();
454 // for (int i= 0; i < localArrays.length; i++) {
455 // int idx= localArrays.length - i - 1;
457 // LocalVariable var= localArrays[idx];
459 // IJavaProject project= cu.getJavaProject();
460 // String typeName= var.typeName;
461 // String baseTypeName= typeName.substring(0, typeName.lastIndexOf('['));
463 // String indexName= getIndex();
464 // String[] excludedNames= completion.getLocalVariableNames();
465 // if (indexName != null) {
466 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
467 // excludedNamesList.add(indexName);
468 // excludedNames= (String[])excludedNamesList.toArray(new
469 // String[excludedNamesList.size()]);
471 // String[] proposals= NamingConventions.suggestLocalVariableNames(project,
472 // var.typePackageName, baseTypeName, 0, excludedNames);
473 // for (int j= 0; j < proposals.length; j++) {
474 // if (!ret.contains(proposals[j]))
475 // ret.add(proposals[j]);
479 // return (String[]) ret.toArray(new String[ret.size()]);
482 * Returns a proposal for a variable name of a local array element,
483 * <code>null</code> if no local array exists.
485 // public String[][] guessGroupedArrayElements() {
486 // ICompilationUnit cu= getCompilationUnit();
488 // return new String[0][];
491 // CompilationUnitCompletion completion= getCompletion();
492 // LocalVariable[] localArrays= completion.findLocalArrays();
494 // String[][] ret= new String[localArrays.length][];
496 // for (int i= 0; i < localArrays.length; i++) {
497 // int idx= localArrays.length - i - 1;
499 // LocalVariable var= localArrays[idx];
501 // IJavaProject project= cu.getJavaProject();
502 // String typeName= var.typeName;
503 // int dim= -1; // we expect at least one array
504 // int lastIndex= typeName.length();
505 // int bracket= typeName.lastIndexOf('[');
506 // while (bracket != -1) {
507 // lastIndex= bracket;
509 // bracket= typeName.lastIndexOf('[', bracket - 1);
511 // typeName= typeName.substring(0, lastIndex);
513 // String indexName= getIndex();
514 // String[] excludedNames= completion.getLocalVariableNames();
515 // if (indexName != null) {
516 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
517 // excludedNamesList.add(indexName);
518 // excludedNames= (String[])excludedNamesList.toArray(new
519 // String[excludedNamesList.size()]);
521 // String[] proposals= NamingConventions.suggestLocalVariableNames(project,
522 // var.typePackageName, typeName, dim, excludedNames);
524 // ret[i]= proposals;
530 * Returns an array index name. 'i', 'j', 'k' are tried until no name
531 * collision with an existing local variable occurs. If all names collide,
532 * <code>null</code> is returned.
534 // public String getIndex() {
535 // CompilationUnitCompletion completion= getCompletion();
536 // String[] proposals= {"i", "j", "k"}; //$NON-NLS-1$ //$NON-NLS-2$
539 // for (int i= 0; i != proposals.length; i++) {
540 // String proposal = proposals[i];
542 // if (!completion.existsLocalName(proposal))
549 * Returns the name of a local collection, <code>null</code> if no local
552 // public String guessCollection() {
553 // return firstOrNull(guessCollections());
556 * Returns the names of local collections.
558 // public String[] guessCollections() {
559 // CompilationUnitCompletion completion= getCompletion();
561 // LocalVariable[] localCollections= completion.findLocalCollections();
562 // String[] ret= new String[localCollections.length];
563 // for (int i= 0; i < ret.length; i++) {
564 // ret[ret.length - i - 1]= localCollections[i].name;
569 // } catch (JavaModelException e) {
570 // JavaPlugin.log(e);
573 // return new String[0];
576 * Returns an iterator name ('iter'). If 'iter' already exists as local
577 * variable, <code>null</code> is returned.
579 // public String getIterator() {
580 // CompilationUnitCompletion completion= getCompletion();
581 // String[] proposals= {"iter"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
583 // for (int i= 0; i != proposals.length; i++) {
584 // String proposal = proposals[i];
586 // if (!completion.existsLocalName(proposal))
592 // public void addIteratorImport() {
593 // ICompilationUnit cu= getCompilationUnit();
599 // Position position= new Position(getCompletionOffset(),
600 // getCompletionLength());
601 // IDocument document= getDocument();
602 // final String category= "__template_position_importer" +
603 // System.currentTimeMillis(); //$NON-NLS-1$
604 // IPositionUpdater updater= new DefaultPositionUpdater(category);
605 // document.addPositionCategory(category);
606 // document.addPositionUpdater(updater);
607 // document.addPosition(position);
609 // CodeGenerationSettings settings=
610 // JavaPreferencesSettings.getCodeGenerationSettings();
611 // ImportsStructure structure= new ImportsStructure(cu,
612 // settings.importOrder, settings.importThreshold, true);
613 // structure.addImport("java.util.Iterator"); //$NON-NLS-1$
614 // structure.create(false, null);
616 // document.removePosition(position);
617 // document.removePositionUpdater(updater);
618 // document.removePositionCategory(category);
620 // setCompletionOffset(position.getOffset());
621 // setCompletionLength(position.getLength());
623 // } catch (CoreException e) {
624 // handleException(null, e);
625 // } catch (BadLocationException e) {
626 // handleException(null, e);
627 // } catch (BadPositionCategoryException e) {
628 // handleException(null, e);
632 * Evaluates a 'java' template in thecontext of a compilation unit
634 public static String evaluateTemplate(Template template,
635 ICompilationUnit compilationUnit, int position)
636 throws CoreException, BadLocationException, TemplateException {
638 TemplateContextType contextType = PHPeclipsePlugin.getDefault()
639 .getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
640 if (contextType == null)
641 throw new CoreException(
644 PHPeclipsePlugin.PLUGIN_ID,
647 .getString("JavaContext.error.message"), null)); //$NON-NLS-1$
649 IDocument document = new Document();
650 if (compilationUnit != null && compilationUnit.exists())
651 document.set(compilationUnit.getSource());
653 JavaContext context = new JavaContext(contextType, document, position,
655 context.setForceEvaluation(true);
657 TemplateBuffer buffer = context.evaluate(template);
660 return buffer.getString();