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.phpdt.ui.PreferenceConstants;
23 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.jface.dialogs.MessageDialog;
29 import org.eclipse.jface.preference.IPreferenceStore;
30 import org.eclipse.jface.text.BadLocationException;
31 import org.eclipse.jface.text.Document;
32 import org.eclipse.jface.text.IDocument;
33 import org.eclipse.jface.text.IRegion;
34 import org.eclipse.jface.text.templates.Template;
35 import org.eclipse.jface.text.templates.TemplateBuffer;
36 import org.eclipse.jface.text.templates.TemplateContextType;
37 import org.eclipse.jface.text.templates.TemplateException;
38 import org.eclipse.jface.text.templates.TemplateTranslator;
39 import org.eclipse.jface.text.templates.TemplateVariable;
40 import org.eclipse.swt.widgets.Shell;
43 * A context for java source.
45 public class JavaContext extends CompilationUnitContext {
47 /** The platform default line delimiter. */
48 private static final String PLATFORM_LINE_DELIMITER= System.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.
56 * @param type the context type.
57 * @param document the document.
58 * @param completionOffset the completion offset within the document.
59 * @param completionLength the completion length.
60 * @param compilationUnit the compilation unit (may be <code>null</code>).
62 public JavaContext(TemplateContextType type, IDocument document, int completionOffset, int completionLength,
63 ICompilationUnit compilationUnit)
65 super(type, document, completionOffset, completionLength, compilationUnit);
69 * Returns the indentation level at the position of code completion.
71 private int getIndentation() {
72 int start= getStart();
73 IDocument document= getDocument();
75 IRegion region= document.getLineInformationOfOffset(start);
76 String lineContent= document.get(region.getOffset(), region.getLength());
77 return Strings.computeIndent(lineContent, CodeFormatterPreferencePage.getTabSize());
78 // return Strings.computeIndent(lineContent, CodeFormatterUtil.getTabWidth());
79 } catch (BadLocationException e) {
87 * @see TemplateContext#evaluate(Template template)
89 public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
91 if (!canEvaluate(template))
92 throw new TemplateException(JavaTemplateMessages.getString("Context.error.cannot.evaluate")); //$NON-NLS-1$
94 TemplateTranslator translator= new TemplateTranslator() {
96 * @see org.eclipse.jface.text.templates.TemplateTranslator#createVariable(java.lang.String, java.lang.String, int[])
98 protected TemplateVariable createVariable(String type, String name, int[] offsets) {
99 return new MultiVariable(type, name, offsets);
102 TemplateBuffer buffer= translator.translate(template);
104 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;
115 IPreferenceStore prefs= PHPeclipsePlugin.getDefault().getPreferenceStore();
116 boolean useCodeFormatter= prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
118 // JavaFormatter formatter= new JavaFormatter(lineDelimiter, getIndentation(), useCodeFormatter);
119 // formatter.format(buffer, this);
125 * @see TemplateContext#canEvaluate(Template templates)
127 public boolean canEvaluate(Template template) {
128 String key= getKey();
130 if (fForceEvaluation)
134 template.matches(key, getContextType().getId()) &&
135 key.length() != 0 && template.getName().toLowerCase().startsWith(key.toLowerCase());
138 public boolean canEvaluate(String identifier) {
139 String prefix = getKey();
141 identifier.toLowerCase().startsWith(prefix.toLowerCase());
144 * @see DocumentTemplateContext#getCompletionPosition();
146 public int getStart() {
149 IDocument document= getDocument();
151 if (getCompletionLength() == 0) {
153 int start= getCompletionOffset();
154 while ((start != 0) && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
157 if ((start != 0) && Character.isUnicodeIdentifierStart(document.getChar(start - 1)))
164 int start= getCompletionOffset();
165 int end= getCompletionOffset() + getCompletionLength();
167 while (start != 0 && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
170 while (start != end && Character.isWhitespace(document.getChar(start)))
174 start= getCompletionOffset();
179 } catch (BadLocationException e) {
180 return super.getStart();
185 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getEnd()
187 public int getEnd() {
189 if (getCompletionLength() == 0)
190 return super.getEnd();
193 IDocument document= getDocument();
195 int start= getCompletionOffset();
196 int end= getCompletionOffset() + getCompletionLength();
198 while (start != end && Character.isWhitespace(document.getChar(end - 1)))
203 } catch (BadLocationException e) {
204 return super.getEnd();
209 * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getKey()
211 public String getKey() {
213 if (getCompletionLength() == 0)
214 return super.getKey();
217 IDocument document= getDocument();
219 int start= getStart();
220 int end= getCompletionOffset();
222 ? document.get(start, end - start)
225 } catch (BadLocationException e) {
226 return super.getKey();
231 * Returns the character before start position of completion.
233 public char getCharacterBeforeStart() {
234 int start= getStart();
239 : getDocument().getChar(start - 1);
241 } catch (BadLocationException e) {
246 private static void handleException(Shell shell, Exception e) {
247 String title= JavaTemplateMessages.getString("JavaContext.error.title"); //$NON-NLS-1$
248 if (e instanceof CoreException)
249 ExceptionHandler.handle((CoreException)e, shell, title, null);
250 else if (e instanceof InvocationTargetException)
251 ExceptionHandler.handle((InvocationTargetException)e, shell, title, null);
253 PHPeclipsePlugin.log(e);
254 MessageDialog.openError(shell, title, e.getMessage());
258 // private CompilationUnitCompletion getCompletion() {
259 // ICompilationUnit compilationUnit= getCompilationUnit();
260 // if (fCompletion == null) {
261 // fCompletion= new CompilationUnitCompletion(compilationUnit);
263 // if (compilationUnit != null) {
265 // compilationUnit.codeComplete(getStart(), fCompletion);
266 // } catch (JavaModelException e) {
272 // return fCompletion;
276 * Returns the name of a guessed local array, <code>null</code> if no local
279 // public String guessArray() {
280 // return firstOrNull(guessArrays());
284 * Returns the name of a guessed local array, <code>null</code> if no local
287 // public String[] guessArrays() {
288 // CompilationUnitCompletion completion= getCompletion();
289 // LocalVariable[] localArrays= completion.findLocalArrays();
291 // String[] ret= new String[localArrays.length];
292 // for (int i= 0; i < ret.length; i++) {
293 // 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
302 // public String guessArrayType() {
303 // return firstOrNull(guessArrayTypes());
306 private String firstOrNull(String[] strings) {
307 if (strings.length > 0)
314 * Returns the name of the type of a local array, <code>null</code> if no local
317 // public String[][] guessGroupedArrayTypes() {
318 // CompilationUnitCompletion completion= getCompletion();
319 // LocalVariable[] localArrays= completion.findLocalArrays();
321 // String[][] ret= new String[localArrays.length][];
323 // for (int i= 0; i < localArrays.length; i++) {
324 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
325 // ret[i]= new String[] {type};
332 * Returns the name of the type of a local array, <code>null</code> if no local
335 // public String[] guessArrayTypes() {
336 // CompilationUnitCompletion completion= getCompletion();
337 // LocalVariable[] localArrays= completion.findLocalArrays();
339 // List ret= new ArrayList();
341 // for (int i= 0; i < localArrays.length; i++) {
342 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
343 // if (!ret.contains(type))
347 // return (String[]) ret.toArray(new String[ret.size()]);
350 private String getArrayTypeFromLocalArray(CompilationUnitCompletion completion, LocalVariable array) {
351 String arrayTypeName= array.typeName;
352 String typeName= getScalarType(arrayTypeName);
353 int dimension= getArrayDimension(arrayTypeName) - 1;
354 Assert.isTrue(dimension >= 0);
356 String qualifiedName= createQualifiedTypeName(array.typePackageName, typeName);
357 String innerTypeName= completion.simplifyTypeName(qualifiedName);
359 return innerTypeName == null
360 ? createArray(typeName, dimension)
361 : createArray(innerTypeName, dimension);
364 private static String createArray(String type, int dimension) {
365 StringBuffer buffer= new StringBuffer(type);
366 for (int i= 0; i < dimension; i++)
367 buffer.append("[]"); //$NON-NLS-1$
368 return buffer.toString();
371 private static String getScalarType(String type) {
372 return type.substring(0, type.indexOf('['));
375 private static int getArrayDimension(String type) {
378 int index= type.indexOf('[');
380 while (index != -1) {
382 index= type.indexOf('[', index + 1);
388 private static String createQualifiedTypeName(String packageName, String className) {
389 StringBuffer buffer= new StringBuffer();
391 if (packageName.length() != 0) {
392 buffer.append(packageName);
395 buffer.append(className);
397 return buffer.toString();
401 * Returns a proposal for a variable name of a local array element, <code>null</code>
402 * if no local array exists.
404 // public String guessArrayElement() {
405 // return firstOrNull(guessArrayElements());
408 * Returns a proposal for a variable name of a local array element, <code>null</code>
409 * if no local array exists.
411 // public String[] guessArrayElements() {
412 // ICompilationUnit cu= getCompilationUnit();
414 // return new String[0];
417 // CompilationUnitCompletion completion= getCompletion();
418 // LocalVariable[] localArrays= completion.findLocalArrays();
420 // List ret= new ArrayList();
422 // for (int i= 0; i < localArrays.length; i++) {
423 // int idx= localArrays.length - i - 1;
425 // LocalVariable var= localArrays[idx];
427 // IJavaProject project= cu.getJavaProject();
428 // String typeName= var.typeName;
429 // String baseTypeName= typeName.substring(0, typeName.lastIndexOf('['));
431 // String indexName= getIndex();
432 // String[] excludedNames= completion.getLocalVariableNames();
433 // if (indexName != null) {
434 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
435 // excludedNamesList.add(indexName);
436 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
438 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, baseTypeName, 0, excludedNames);
439 // for (int j= 0; j < proposals.length; j++) {
440 // if (!ret.contains(proposals[j]))
441 // ret.add(proposals[j]);
445 // return (String[]) ret.toArray(new String[ret.size()]);
449 * Returns a proposal for a variable name of a local array element, <code>null</code>
450 * if no local array exists.
452 // public String[][] guessGroupedArrayElements() {
453 // ICompilationUnit cu= getCompilationUnit();
455 // return new String[0][];
458 // CompilationUnitCompletion completion= getCompletion();
459 // LocalVariable[] localArrays= completion.findLocalArrays();
461 // String[][] ret= new String[localArrays.length][];
463 // for (int i= 0; i < localArrays.length; i++) {
464 // int idx= localArrays.length - i - 1;
466 // LocalVariable var= localArrays[idx];
468 // IJavaProject project= cu.getJavaProject();
469 // String typeName= var.typeName;
470 // int dim= -1; // we expect at least one array
471 // int lastIndex= typeName.length();
472 // int bracket= typeName.lastIndexOf('[');
473 // while (bracket != -1) {
474 // lastIndex= bracket;
476 // bracket= typeName.lastIndexOf('[', bracket - 1);
478 // typeName= typeName.substring(0, lastIndex);
480 // String indexName= getIndex();
481 // String[] excludedNames= completion.getLocalVariableNames();
482 // if (indexName != null) {
483 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
484 // excludedNamesList.add(indexName);
485 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
487 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, typeName, dim, excludedNames);
489 // ret[i]= proposals;
496 * Returns an array index name. 'i', 'j', 'k' are tried until no name collision with
497 * an existing local variable occurs. If all names collide, <code>null</code> is returned.
499 // public String getIndex() {
500 // CompilationUnitCompletion completion= getCompletion();
501 // String[] proposals= {"i", "j", "k"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
503 // for (int i= 0; i != proposals.length; i++) {
504 // String proposal = proposals[i];
506 // if (!completion.existsLocalName(proposal))
514 * Returns the name of a local collection, <code>null</code> if no local collection
517 // public String guessCollection() {
518 // return firstOrNull(guessCollections());
522 * Returns the names of local collections.
524 // public String[] guessCollections() {
525 // CompilationUnitCompletion completion= getCompletion();
527 // LocalVariable[] localCollections= completion.findLocalCollections();
528 // String[] ret= new String[localCollections.length];
529 // for (int i= 0; i < ret.length; i++) {
530 // ret[ret.length - i - 1]= localCollections[i].name;
535 // } catch (JavaModelException e) {
536 // JavaPlugin.log(e);
539 // return new String[0];
544 * Returns an iterator name ('iter'). If 'iter' already exists as local variable,
545 * <code>null</code> is returned.
547 // public String getIterator() {
548 // CompilationUnitCompletion completion= getCompletion();
549 // String[] proposals= {"iter"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
551 // for (int i= 0; i != proposals.length; i++) {
552 // String proposal = proposals[i];
554 // if (!completion.existsLocalName(proposal))
562 // public void addIteratorImport() {
563 // ICompilationUnit cu= getCompilationUnit();
569 // Position position= new Position(getCompletionOffset(), getCompletionLength());
570 // IDocument document= getDocument();
571 // final String category= "__template_position_importer" + System.currentTimeMillis(); //$NON-NLS-1$
572 // IPositionUpdater updater= new DefaultPositionUpdater(category);
573 // document.addPositionCategory(category);
574 // document.addPositionUpdater(updater);
575 // document.addPosition(position);
577 // CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings();
578 // ImportsStructure structure= new ImportsStructure(cu, settings.importOrder, settings.importThreshold, true);
579 // structure.addImport("java.util.Iterator"); //$NON-NLS-1$
580 // structure.create(false, null);
582 // document.removePosition(position);
583 // document.removePositionUpdater(updater);
584 // document.removePositionCategory(category);
586 // setCompletionOffset(position.getOffset());
587 // setCompletionLength(position.getLength());
589 // } catch (CoreException e) {
590 // handleException(null, e);
591 // } catch (BadLocationException e) {
592 // handleException(null, e);
593 // } catch (BadPositionCategoryException e) {
594 // handleException(null, e);
599 * Evaluates a 'java' template in thecontext of a compilation unit
601 public static String evaluateTemplate(Template template, ICompilationUnit compilationUnit, int position) throws CoreException, BadLocationException, TemplateException {
603 TemplateContextType contextType= PHPeclipsePlugin.getDefault().getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
604 if (contextType == null)
605 throw new CoreException(new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.ERROR, JavaTemplateMessages.getString("JavaContext.error.message"), null)); //$NON-NLS-1$
607 IDocument document= new Document();
608 if (compilationUnit != null && compilationUnit.exists())
609 document.set(compilationUnit.getSource());
611 JavaContext context= new JavaContext(contextType, document, position, 0, compilationUnit);
612 context.setForceEvaluation(true);
614 TemplateBuffer buffer= context.evaluate(template);
617 return buffer.getString();