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.
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, int completionOffset, int completionLength,
68 ICompilationUnit compilationUnit) {
69 super(type, document, completionOffset, completionLength, compilationUnit);
73 * Returns the indentation level at the position of code completion.
75 private int getIndentation() {
76 int start = getStart();
77 IDocument document = getDocument();
79 IRegion region = document.getLineInformationOfOffset(start);
80 String lineContent = document.get(region.getOffset(), region.getLength());
81 return Strings.computeIndent(lineContent, CodeFormatterPreferencePage.getTabSize());
82 // return Strings.computeIndent(lineContent, CodeFormatterUtil.getTabWidth());
83 } catch (BadLocationException e) {
89 * @see TemplateContext#evaluate(Template template)
91 public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
93 if (!canEvaluate(template))
94 throw new TemplateException(JavaTemplateMessages.getString("Context.error.cannot.evaluate")); //$NON-NLS-1$
96 TemplateTranslator translator = new TemplateTranslator() {
98 * @see org.eclipse.jface.text.templates.TemplateTranslator#createVariable(java.lang.String, java.lang.String, int[])
100 protected TemplateVariable createVariable(String type, String name, int[] offsets) {
101 return new MultiVariable(type, name, offsets);
104 TemplateBuffer buffer = translator.translate(template);
106 getContextType().resolve(buffer, this);
107 String lineDelimiter = null;
109 lineDelimiter = getDocument().getLineDelimiter(0);
110 } catch (BadLocationException e) {
113 if (lineDelimiter == null)
114 lineDelimiter = PLATFORM_LINE_DELIMITER;
115 IPreferenceStore prefs = PHPeclipsePlugin.getDefault().getPreferenceStore();
117 // boolean useCodeFormatter = prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
118 boolean useCodeFormatter = false;
121 JavaFormatter formatter = new JavaFormatter(lineDelimiter, getIndentation(), useCodeFormatter);
122 formatter.format(buffer, this);
124 // String res = buffer.getString();
125 // res = res.replaceAll("\n","/n");
126 // res = res.replaceAll("\t","/t");
127 // System.out.println(res);
133 * @see TemplateContext#canEvaluate(Template templates)
135 public boolean canEvaluate(Template template) {
136 String key = getKey();
138 if (fForceEvaluation)
141 return template.matches(key, getContextType().getId()) && key.length() != 0
142 && template.getName().toLowerCase().startsWith(key.toLowerCase());
145 public boolean canEvaluate(String identifier) {
146 String prefix = getKey();
147 return identifier.toLowerCase().startsWith(prefix.toLowerCase());
151 * @see DocumentTemplateContext#getCompletionPosition();
153 public int getStart() {
156 IDocument document = getDocument();
158 if (getCompletionLength() == 0) {
160 int start = getCompletionOffset();
161 while ((start != 0) && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
164 if ((start != 0) && Character.isUnicodeIdentifierStart(document.getChar(start - 1)))
171 int start = getCompletionOffset();
172 int end = getCompletionOffset() + getCompletionLength();
174 while (start != 0 && Character.isUnicodeIdentifierPart(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();
224 IDocument document = getDocument();
226 int start = getStart();
227 int end = getCompletionOffset();
228 return start <= end ? document.get(start, end - start) : ""; //$NON-NLS-1$
230 } catch (BadLocationException e) {
231 return super.getKey();
236 * Returns the character before start position of completion.
238 public char getCharacterBeforeStart() {
239 int start = getStart();
242 return start == 0 ? ' ' : getDocument().getChar(start - 1);
244 } catch (BadLocationException e) {
249 private static void handleException(Shell shell, Exception e) {
250 String title = JavaTemplateMessages.getString("JavaContext.error.title"); //$NON-NLS-1$
251 if (e instanceof CoreException)
252 ExceptionHandler.handle((CoreException) e, shell, title, null);
253 else if (e instanceof InvocationTargetException)
254 ExceptionHandler.handle((InvocationTargetException) e, shell, title, null);
256 PHPeclipsePlugin.log(e);
257 MessageDialog.openError(shell, title, e.getMessage());
261 // private CompilationUnitCompletion getCompletion() {
262 // ICompilationUnit compilationUnit= getCompilationUnit();
263 // if (fCompletion == null) {
264 // fCompletion= new CompilationUnitCompletion(compilationUnit);
266 // if (compilationUnit != null) {
268 // compilationUnit.codeComplete(getStart(), fCompletion);
269 // } catch (JavaModelException e) {
275 // return fCompletion;
279 * Returns the name of a guessed local array, <code>null</code> if no local array exists.
281 // public String guessArray() {
282 // return firstOrNull(guessArrays());
285 * Returns the name of a guessed local array, <code>null</code> if no local array exists.
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;
298 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
300 // public String guessArrayType() {
301 // return firstOrNull(guessArrayTypes());
303 private String firstOrNull(String[] strings) {
304 if (strings.length > 0)
311 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
313 // public String[][] guessGroupedArrayTypes() {
314 // CompilationUnitCompletion completion= getCompletion();
315 // LocalVariable[] localArrays= completion.findLocalArrays();
317 // String[][] ret= new String[localArrays.length][];
319 // for (int i= 0; i < localArrays.length; i++) {
320 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
321 // ret[i]= new String[] {type};
327 * Returns the name of the type of a local array, <code>null</code> if no local array exists.
329 // public String[] guessArrayTypes() {
330 // CompilationUnitCompletion completion= getCompletion();
331 // LocalVariable[] localArrays= completion.findLocalArrays();
333 // List ret= new ArrayList();
335 // for (int i= 0; i < localArrays.length; i++) {
336 // String type= getArrayTypeFromLocalArray(completion, localArrays[localArrays.length - i - 1]);
337 // if (!ret.contains(type))
341 // return (String[]) ret.toArray(new String[ret.size()]);
343 private String getArrayTypeFromLocalArray(CompilationUnitCompletion completion, LocalVariable array) {
344 String arrayTypeName = array.typeName;
345 String typeName = getScalarType(arrayTypeName);
346 int dimension = getArrayDimension(arrayTypeName) - 1;
347 Assert.isTrue(dimension >= 0);
349 String qualifiedName = createQualifiedTypeName(array.typePackageName, typeName);
350 String innerTypeName = completion.simplifyTypeName(qualifiedName);
352 return innerTypeName == null ? createArray(typeName, dimension) : createArray(innerTypeName, dimension);
355 private static String createArray(String type, int dimension) {
356 StringBuffer buffer = new StringBuffer(type);
357 for (int i = 0; i < dimension; i++)
358 buffer.append("[]"); //$NON-NLS-1$
359 return buffer.toString();
362 private static String getScalarType(String type) {
363 return type.substring(0, type.indexOf('['));
366 private static int getArrayDimension(String type) {
369 int index = type.indexOf('[');
371 while (index != -1) {
373 index = type.indexOf('[', index + 1);
379 private static String createQualifiedTypeName(String packageName, String className) {
380 StringBuffer buffer = new StringBuffer();
382 if (packageName.length() != 0) {
383 buffer.append(packageName);
386 buffer.append(className);
388 return buffer.toString();
392 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
394 // public String guessArrayElement() {
395 // return firstOrNull(guessArrayElements());
398 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
400 // public String[] guessArrayElements() {
401 // ICompilationUnit cu= getCompilationUnit();
403 // return new String[0];
406 // CompilationUnitCompletion completion= getCompletion();
407 // LocalVariable[] localArrays= completion.findLocalArrays();
409 // List ret= new ArrayList();
411 // for (int i= 0; i < localArrays.length; i++) {
412 // int idx= localArrays.length - i - 1;
414 // LocalVariable var= localArrays[idx];
416 // IJavaProject project= cu.getJavaProject();
417 // String typeName= var.typeName;
418 // String baseTypeName= typeName.substring(0, typeName.lastIndexOf('['));
420 // String indexName= getIndex();
421 // String[] excludedNames= completion.getLocalVariableNames();
422 // if (indexName != null) {
423 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
424 // excludedNamesList.add(indexName);
425 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
427 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, baseTypeName, 0, excludedNames);
428 // for (int j= 0; j < proposals.length; j++) {
429 // if (!ret.contains(proposals[j]))
430 // ret.add(proposals[j]);
434 // return (String[]) ret.toArray(new String[ret.size()]);
437 * Returns a proposal for a variable name of a local array element, <code>null</code> if no local array exists.
439 // public String[][] guessGroupedArrayElements() {
440 // ICompilationUnit cu= getCompilationUnit();
442 // return new String[0][];
445 // CompilationUnitCompletion completion= getCompletion();
446 // LocalVariable[] localArrays= completion.findLocalArrays();
448 // String[][] ret= new String[localArrays.length][];
450 // for (int i= 0; i < localArrays.length; i++) {
451 // int idx= localArrays.length - i - 1;
453 // LocalVariable var= localArrays[idx];
455 // IJavaProject project= cu.getJavaProject();
456 // String typeName= var.typeName;
457 // int dim= -1; // we expect at least one array
458 // int lastIndex= typeName.length();
459 // int bracket= typeName.lastIndexOf('[');
460 // while (bracket != -1) {
461 // lastIndex= bracket;
463 // bracket= typeName.lastIndexOf('[', bracket - 1);
465 // typeName= typeName.substring(0, lastIndex);
467 // String indexName= getIndex();
468 // String[] excludedNames= completion.getLocalVariableNames();
469 // if (indexName != null) {
470 // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
471 // excludedNamesList.add(indexName);
472 // excludedNames= (String[])excludedNamesList.toArray(new String[excludedNamesList.size()]);
474 // String[] proposals= NamingConventions.suggestLocalVariableNames(project, var.typePackageName, typeName, dim, excludedNames);
476 // ret[i]= proposals;
482 * Returns an array index name. 'i', 'j', 'k' are tried until no name collision with an existing local variable occurs. If all
483 * names collide, <code>null</code> is returned.
485 // public String getIndex() {
486 // CompilationUnitCompletion completion= getCompletion();
487 // String[] proposals= {"i", "j", "k"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
489 // for (int i= 0; i != proposals.length; i++) {
490 // String proposal = proposals[i];
492 // if (!completion.existsLocalName(proposal))
499 * Returns the name of a local collection, <code>null</code> if no local collection exists.
501 // public String guessCollection() {
502 // return firstOrNull(guessCollections());
505 * Returns the names of local collections.
507 // public String[] guessCollections() {
508 // CompilationUnitCompletion completion= getCompletion();
510 // LocalVariable[] localCollections= completion.findLocalCollections();
511 // String[] ret= new String[localCollections.length];
512 // for (int i= 0; i < ret.length; i++) {
513 // ret[ret.length - i - 1]= localCollections[i].name;
518 // } catch (JavaModelException e) {
519 // JavaPlugin.log(e);
522 // return new String[0];
525 * Returns an iterator name ('iter'). If 'iter' already exists as local variable, <code>null</code> is returned.
527 // public String getIterator() {
528 // CompilationUnitCompletion completion= getCompletion();
529 // String[] proposals= {"iter"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
531 // for (int i= 0; i != proposals.length; i++) {
532 // String proposal = proposals[i];
534 // if (!completion.existsLocalName(proposal))
540 // public void addIteratorImport() {
541 // ICompilationUnit cu= getCompilationUnit();
547 // Position position= new Position(getCompletionOffset(), getCompletionLength());
548 // IDocument document= getDocument();
549 // final String category= "__template_position_importer" + System.currentTimeMillis(); //$NON-NLS-1$
550 // IPositionUpdater updater= new DefaultPositionUpdater(category);
551 // document.addPositionCategory(category);
552 // document.addPositionUpdater(updater);
553 // document.addPosition(position);
555 // CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings();
556 // ImportsStructure structure= new ImportsStructure(cu, settings.importOrder, settings.importThreshold, true);
557 // structure.addImport("java.util.Iterator"); //$NON-NLS-1$
558 // structure.create(false, null);
560 // document.removePosition(position);
561 // document.removePositionUpdater(updater);
562 // document.removePositionCategory(category);
564 // setCompletionOffset(position.getOffset());
565 // setCompletionLength(position.getLength());
567 // } catch (CoreException e) {
568 // handleException(null, e);
569 // } catch (BadLocationException e) {
570 // handleException(null, e);
571 // } catch (BadPositionCategoryException e) {
572 // handleException(null, e);
576 * Evaluates a 'java' template in thecontext of a compilation unit
578 public static String evaluateTemplate(Template template, ICompilationUnit compilationUnit, int position) throws CoreException,
579 BadLocationException, TemplateException {
581 TemplateContextType contextType = PHPeclipsePlugin.getDefault().getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
582 if (contextType == null)
583 throw new CoreException(new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.ERROR, JavaTemplateMessages
584 .getString("JavaContext.error.message"), null)); //$NON-NLS-1$
586 IDocument document = new Document();
587 if (compilationUnit != null && compilationUnit.exists())
588 document.set(compilationUnit.getSource());
590 JavaContext context = new JavaContext(contextType, document, position, 0, compilationUnit);
591 context.setForceEvaluation(true);
593 TemplateBuffer buffer = context.evaluate(template);
596 return buffer.getString();