0102646e5c52c1607f9c74299e672679374a0ae4
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / corext / template / php / JavaContext.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.corext.template.php;
12
13 import java.lang.reflect.InvocationTargetException;
14
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;
23 import net.sourceforge.phpeclipse.ui.WebUI;
24
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;
41
42 /**
43  * A context for java source.
44  */
45 public class JavaContext extends CompilationUnitContext {
46
47         /** The platform default line delimiter. */
48         private static final String PLATFORM_LINE_DELIMITER = System
49                         .getProperty("line.separator"); //$NON-NLS-1$
50
51         /** A code completion requestor for guessing local variable names. */
52         private CompilationUnitCompletion fCompletion;
53
54         /**
55          * Creates a java template context.
56          * 
57          * @param type
58          *            the context type.
59          * @param document
60          *            the document.
61          * @param completionOffset
62          *            the completion offset within the document.
63          * @param completionLength
64          *            the completion length.
65          * @param compilationUnit
66          *            the compilation unit (may be <code>null</code>).
67          */
68         public JavaContext(TemplateContextType type, IDocument document,
69                         int completionOffset, int completionLength,
70                         ICompilationUnit compilationUnit) {
71                 super(type, document, completionOffset, completionLength,
72                                 compilationUnit);
73         }
74
75         /**
76          * Returns the indentation level at the position of code completion.
77          */
78         private int getIndentation() {
79                 int start = getStart();
80                 IDocument document = getDocument();
81                 try {
82                         IRegion region = document.getLineInformationOfOffset(start);
83                         String lineContent = document.get(region.getOffset(), region
84                                         .getLength());
85                         return Strings.computeIndent(lineContent,
86                                         CodeFormatterPreferencePage.getTabSize());
87                         // return Strings.computeIndent(lineContent,
88                         // CodeFormatterUtil.getTabWidth());
89                 } catch (BadLocationException e) {
90                         return 0;
91                 }
92         }
93
94         /*
95          * @see TemplateContext#evaluate(Template template)
96          */
97         public TemplateBuffer evaluate(Template template)
98                         throws BadLocationException, TemplateException {
99
100                 if (!canEvaluate(template))
101                         throw new TemplateException(JavaTemplateMessages
102                                         .getString("Context.error.cannot.evaluate")); //$NON-NLS-1$
103
104                 TemplateTranslator translator = new TemplateTranslator() {
105                         /*
106                          * @see org.eclipse.jface.text.templates.TemplateTranslator#createVariable(java.lang.String,
107                          *      java.lang.String, int[])
108                          */
109                         protected TemplateVariable createVariable(String type, String name,
110                                         int[] offsets) {
111                                 return new MultiVariable(type, name, offsets);
112                         }
113                 };
114                 TemplateBuffer buffer = translator.translate(template);
115
116                 getContextType().resolve(buffer, this);
117                 String lineDelimiter = null;
118                 try {
119                         lineDelimiter = getDocument().getLineDelimiter(0);
120                 } catch (BadLocationException e) {
121                 }
122
123                 if (lineDelimiter == null)
124                         lineDelimiter = PLATFORM_LINE_DELIMITER;
125                 IPreferenceStore prefs = WebUI.getDefault()
126                                 .getPreferenceStore();
127                 // axelcl start
128                 // boolean useCodeFormatter =
129                 // prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
130                 boolean useCodeFormatter = false;
131                 // axelcl end
132
133                 JavaFormatter formatter = new JavaFormatter(lineDelimiter,
134                                 getIndentation(), useCodeFormatter);
135                 formatter.format(buffer, this);
136                 // debug start
137                 // String res = buffer.getString();
138                 // res = res.replaceAll("\n","/n");
139                 // res = res.replaceAll("\t","/t");
140                 // System.out.println(res);
141                 // debug end
142                 return buffer;
143         }
144
145         /*
146          * @see TemplateContext#canEvaluate(Template templates)
147          */
148         public boolean canEvaluate(Template template) {
149                 String key = getKey();
150
151                 if (fForceEvaluation)
152                         return true;
153
154                 return template.matches(key, getContextType().getId())
155                                 && key.length() != 0
156                                 && template.getName().toLowerCase().startsWith(
157                                                 key.toLowerCase());
158         }
159
160         public boolean canEvaluate(String identifier) {
161                 String prefix = getKey();
162                 return identifier.toLowerCase().startsWith(prefix.toLowerCase());
163         }
164
165         /*
166          * @see DocumentTemplateContext#getCompletionPosition();
167          */
168         public int getStart() {
169
170                 try {
171                         IDocument document = getDocument();
172
173                         if (getCompletionLength() == 0) {
174
175                                 int start = getCompletionOffset();
176                                 while ((start != 0)
177                                                 && Character.isUnicodeIdentifierPart(document
178                                                                 .getChar(start - 1)))
179                                         start--;
180
181                                 if ((start != 0)
182                                                 && (Character.isUnicodeIdentifierStart(document
183                                                                 .getChar(start - 1)) || (document
184                                                                 .getChar(start - 1) == '$')))
185                                         start--;
186
187                                 return start;
188
189                         } else {
190
191                                 int start = getCompletionOffset();
192                                 int end = getCompletionOffset() + getCompletionLength();
193
194                                 while (start != 0
195                                                 && Character.isUnicodeIdentifierPart(document
196                                                                 .getChar(start - 1)))
197                                         start--;
198                                 if ((start != 0)
199                                                 && (Character.isUnicodeIdentifierStart(document
200                                                                 .getChar(start - 1)) || (document
201                                                                 .getChar(start - 1) == '$')))
202                                         start--;
203                                 while (start != end
204                                                 && Character.isWhitespace(document.getChar(start)))
205                                         start++;
206
207                                 if (start == end)
208                                         start = getCompletionOffset();
209
210                                 return start;
211                         }
212
213                 } catch (BadLocationException e) {
214                         return super.getStart();
215                 }
216         }
217
218         /*
219          * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getEnd()
220          */
221         public int getEnd() {
222
223                 if (getCompletionLength() == 0)
224                         return super.getEnd();
225
226                 try {
227                         IDocument document = getDocument();
228
229                         int start = getCompletionOffset();
230                         int end = getCompletionOffset() + getCompletionLength();
231
232                         while (start != end
233                                         && Character.isWhitespace(document.getChar(end - 1)))
234                                 end--;
235
236                         return end;
237
238                 } catch (BadLocationException e) {
239                         return super.getEnd();
240                 }
241         }
242
243         /*
244          * @see net.sourceforge.phpdt.internal.corext.template.DocumentTemplateContext#getKey()
245          */
246         public String getKey() {
247
248                 // if (getCompletionLength() == 0) {
249                 // return super.getKey();
250                 // }
251
252                 try {
253                         IDocument document = getDocument();
254
255                         int start = getStart();
256                         int end = getCompletionOffset();
257                         return start <= end ? document.get(start, end - start) : ""; //$NON-NLS-1$
258
259                 } catch (BadLocationException e) {
260                         return super.getKey();
261                 }
262         }
263
264         /**
265          * Returns the character before start position of completion.
266          */
267         public char getCharacterBeforeStart() {
268                 int start = getStart();
269
270                 try {
271                         return start == 0 ? ' ' : getDocument().getChar(start - 1);
272
273                 } catch (BadLocationException e) {
274                         return ' ';
275                 }
276         }
277
278         private static void handleException(Shell shell, Exception e) {
279                 String title = JavaTemplateMessages
280                                 .getString("JavaContext.error.title"); //$NON-NLS-1$
281                 if (e instanceof CoreException)
282                         ExceptionHandler.handle((CoreException) e, shell, title, null);
283                 else if (e instanceof InvocationTargetException)
284                         ExceptionHandler.handle((InvocationTargetException) e, shell,
285                                         title, null);
286                 else {
287                         PHPeclipsePlugin.log(e);
288                         MessageDialog.openError(shell, title, e.getMessage());
289                 }
290         }
291
292         // private CompilationUnitCompletion getCompletion() {
293         // ICompilationUnit compilationUnit= getCompilationUnit();
294         // if (fCompletion == null) {
295         // fCompletion= new CompilationUnitCompletion(compilationUnit);
296         //                      
297         // if (compilationUnit != null) {
298         // try {
299         // compilationUnit.codeComplete(getStart(), fCompletion);
300         // } catch (JavaModelException e) {
301         // // ignore
302         // }
303         // }
304         // }
305         //              
306         // return fCompletion;
307         // }
308
309         /**
310          * Returns the name of a guessed local array, <code>null</code> if no
311          * local array exists.
312          */
313         // public String guessArray() {
314         // return firstOrNull(guessArrays());
315         // }
316         /**
317          * Returns the name of a guessed local array, <code>null</code> if no
318          * local array exists.
319          */
320         // public String[] guessArrays() {
321         // CompilationUnitCompletion completion= getCompletion();
322         // LocalVariable[] localArrays= completion.findLocalArrays();
323         //                              
324         // String[] ret= new String[localArrays.length];
325         // for (int i= 0; i < ret.length; i++) {
326         // ret[ret.length - i - 1]= localArrays[i].name;
327         // }
328         // return ret;
329         // }
330         /**
331          * Returns the name of the type of a local array, <code>null</code> if no
332          * local array exists.
333          */
334         // public String guessArrayType() {
335         // return firstOrNull(guessArrayTypes());
336         // }
337         private String firstOrNull(String[] strings) {
338                 if (strings.length > 0)
339                         return strings[0];
340                 else
341                         return null;
342         }
343
344         /**
345          * Returns the name of the type of a local array, <code>null</code> if no
346          * local array exists.
347          */
348         // public String[][] guessGroupedArrayTypes() {
349         // CompilationUnitCompletion completion= getCompletion();
350         // LocalVariable[] localArrays= completion.findLocalArrays();
351         //              
352         // String[][] ret= new String[localArrays.length][];
353         //              
354         // for (int i= 0; i < localArrays.length; i++) {
355         // String type= getArrayTypeFromLocalArray(completion,
356         // localArrays[localArrays.length - i - 1]);
357         // ret[i]= new String[] {type};
358         // }
359         //              
360         // return ret;
361         // }
362         /**
363          * Returns the name of the type of a local array, <code>null</code> if no
364          * local array exists.
365          */
366         // public String[] guessArrayTypes() {
367         // CompilationUnitCompletion completion= getCompletion();
368         // LocalVariable[] localArrays= completion.findLocalArrays();
369         //              
370         // List ret= new ArrayList();
371         //              
372         // for (int i= 0; i < localArrays.length; i++) {
373         // String type= getArrayTypeFromLocalArray(completion,
374         // localArrays[localArrays.length - i - 1]);
375         // if (!ret.contains(type))
376         // ret.add(type);
377         // }
378         //              
379         // return (String[]) ret.toArray(new String[ret.size()]);
380         // }
381         private String getArrayTypeFromLocalArray(
382                         CompilationUnitCompletion completion, LocalVariable array) {
383                 String arrayTypeName = array.typeName;
384                 String typeName = getScalarType(arrayTypeName);
385                 int dimension = getArrayDimension(arrayTypeName) - 1;
386                 Assert.isTrue(dimension >= 0);
387
388                 String qualifiedName = createQualifiedTypeName(array.typePackageName,
389                                 typeName);
390                 String innerTypeName = completion.simplifyTypeName(qualifiedName);
391
392                 return innerTypeName == null ? createArray(typeName, dimension)
393                                 : createArray(innerTypeName, dimension);
394         }
395
396         private static String createArray(String type, int dimension) {
397                 StringBuffer buffer = new StringBuffer(type);
398                 for (int i = 0; i < dimension; i++)
399                         buffer.append("[]"); //$NON-NLS-1$
400                 return buffer.toString();
401         }
402
403         private static String getScalarType(String type) {
404                 return type.substring(0, type.indexOf('['));
405         }
406
407         private static int getArrayDimension(String type) {
408
409                 int dimension = 0;
410                 int index = type.indexOf('[');
411
412                 while (index != -1) {
413                         dimension++;
414                         index = type.indexOf('[', index + 1);
415                 }
416
417                 return dimension;
418         }
419
420         private static String createQualifiedTypeName(String packageName,
421                         String className) {
422                 StringBuffer buffer = new StringBuffer();
423
424                 if (packageName.length() != 0) {
425                         buffer.append(packageName);
426                         buffer.append('.');
427                 }
428                 buffer.append(className);
429
430                 return buffer.toString();
431         }
432
433         /**
434          * Returns a proposal for a variable name of a local array element,
435          * <code>null</code> if no local array exists.
436          */
437         // public String guessArrayElement() {
438         // return firstOrNull(guessArrayElements());
439         // }
440         /**
441          * Returns a proposal for a variable name of a local array element,
442          * <code>null</code> if no local array exists.
443          */
444         // public String[] guessArrayElements() {
445         // ICompilationUnit cu= getCompilationUnit();
446         // if (cu == null) {
447         // return new String[0];
448         // }
449         //              
450         // CompilationUnitCompletion completion= getCompletion();
451         // LocalVariable[] localArrays= completion.findLocalArrays();
452         //              
453         // List ret= new ArrayList();
454         //              
455         // for (int i= 0; i < localArrays.length; i++) {
456         // int idx= localArrays.length - i - 1;
457         //                      
458         // LocalVariable var= localArrays[idx];
459         //                      
460         // IJavaProject project= cu.getJavaProject();
461         // String typeName= var.typeName;
462         // String baseTypeName= typeName.substring(0, typeName.lastIndexOf('['));
463         //
464         // String indexName= getIndex();
465         // String[] excludedNames= completion.getLocalVariableNames();
466         // if (indexName != null) {
467         // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
468         // excludedNamesList.add(indexName);
469         // excludedNames= (String[])excludedNamesList.toArray(new
470         // String[excludedNamesList.size()]);
471         // }
472         // String[] proposals= NamingConventions.suggestLocalVariableNames(project,
473         // var.typePackageName, baseTypeName, 0, excludedNames);
474         // for (int j= 0; j < proposals.length; j++) {
475         // if (!ret.contains(proposals[j]))
476         // ret.add(proposals[j]);
477         // }
478         // }
479         //              
480         // return (String[]) ret.toArray(new String[ret.size()]);
481         // }
482         /**
483          * Returns a proposal for a variable name of a local array element,
484          * <code>null</code> if no local array exists.
485          */
486         // public String[][] guessGroupedArrayElements() {
487         // ICompilationUnit cu= getCompilationUnit();
488         // if (cu == null) {
489         // return new String[0][];
490         // }
491         //              
492         // CompilationUnitCompletion completion= getCompletion();
493         // LocalVariable[] localArrays= completion.findLocalArrays();
494         //              
495         // String[][] ret= new String[localArrays.length][];
496         //              
497         // for (int i= 0; i < localArrays.length; i++) {
498         // int idx= localArrays.length - i - 1;
499         //                      
500         // LocalVariable var= localArrays[idx];
501         //                      
502         // IJavaProject project= cu.getJavaProject();
503         // String typeName= var.typeName;
504         // int dim= -1; // we expect at least one array
505         // int lastIndex= typeName.length();
506         // int bracket= typeName.lastIndexOf('[');
507         // while (bracket != -1) {
508         // lastIndex= bracket;
509         // dim++;
510         // bracket= typeName.lastIndexOf('[', bracket - 1);
511         // }
512         // typeName= typeName.substring(0, lastIndex);
513         //                      
514         // String indexName= getIndex();
515         // String[] excludedNames= completion.getLocalVariableNames();
516         // if (indexName != null) {
517         // ArrayList excludedNamesList= new ArrayList(Arrays.asList(excludedNames));
518         // excludedNamesList.add(indexName);
519         // excludedNames= (String[])excludedNamesList.toArray(new
520         // String[excludedNamesList.size()]);
521         // }
522         // String[] proposals= NamingConventions.suggestLocalVariableNames(project,
523         // var.typePackageName, typeName, dim, excludedNames);
524         //                      
525         // ret[i]= proposals;
526         // }
527         //              
528         // return ret;
529         // }
530         /**
531          * Returns an array index name. 'i', 'j', 'k' are tried until no name
532          * collision with an existing local variable occurs. If all names collide,
533          * <code>null</code> is returned.
534          */
535         // public String getIndex() {
536         // CompilationUnitCompletion completion= getCompletion();
537         // String[] proposals= {"i", "j", "k"}; //$NON-NLS-1$ //$NON-NLS-2$
538         // //$NON-NLS-3$
539         //              
540         // for (int i= 0; i != proposals.length; i++) {
541         // String proposal = proposals[i];
542         //
543         // if (!completion.existsLocalName(proposal))
544         // return proposal;
545         // }
546         //
547         // return null;
548         // }
549         /**
550          * Returns the name of a local collection, <code>null</code> if no local
551          * collection exists.
552          */
553         // public String guessCollection() {
554         // return firstOrNull(guessCollections());
555         // }
556         /**
557          * Returns the names of local collections.
558          */
559         // public String[] guessCollections() {
560         // CompilationUnitCompletion completion= getCompletion();
561         // try {
562         // LocalVariable[] localCollections= completion.findLocalCollections();
563         // String[] ret= new String[localCollections.length];
564         // for (int i= 0; i < ret.length; i++) {
565         // ret[ret.length - i - 1]= localCollections[i].name;
566         // }
567         //                      
568         // return ret;
569         //
570         // } catch (JavaModelException e) {
571         // JavaPlugin.log(e);
572         // }
573         //
574         // return new String[0];
575         // }
576         /**
577          * Returns an iterator name ('iter'). If 'iter' already exists as local
578          * variable, <code>null</code> is returned.
579          */
580         // public String getIterator() {
581         // CompilationUnitCompletion completion= getCompletion();
582         // String[] proposals= {"iter"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
583         //              
584         // for (int i= 0; i != proposals.length; i++) {
585         // String proposal = proposals[i];
586         //
587         // if (!completion.existsLocalName(proposal))
588         // return proposal;
589         // }
590         //
591         // return null;
592         // }
593         // public void addIteratorImport() {
594         // ICompilationUnit cu= getCompilationUnit();
595         // if (cu == null) {
596         // return;
597         // }
598         //      
599         // try {
600         // Position position= new Position(getCompletionOffset(),
601         // getCompletionLength());
602         // IDocument document= getDocument();
603         // final String category= "__template_position_importer" +
604         // System.currentTimeMillis(); //$NON-NLS-1$
605         // IPositionUpdater updater= new DefaultPositionUpdater(category);
606         // document.addPositionCategory(category);
607         // document.addPositionUpdater(updater);
608         // document.addPosition(position);
609         //
610         // CodeGenerationSettings settings=
611         // JavaPreferencesSettings.getCodeGenerationSettings();
612         // ImportsStructure structure= new ImportsStructure(cu,
613         // settings.importOrder, settings.importThreshold, true);
614         // structure.addImport("java.util.Iterator"); //$NON-NLS-1$
615         // structure.create(false, null);
616         //
617         // document.removePosition(position);
618         // document.removePositionUpdater(updater);
619         // document.removePositionCategory(category);
620         //                      
621         // setCompletionOffset(position.getOffset());
622         // setCompletionLength(position.getLength());
623         //                      
624         // } catch (CoreException e) {
625         // handleException(null, e);
626         // } catch (BadLocationException e) {
627         // handleException(null, e);
628         // } catch (BadPositionCategoryException e) {
629         // handleException(null, e);
630         // }
631         // }
632         /**
633          * Evaluates a 'java' template in thecontext of a compilation unit
634          */
635         public static String evaluateTemplate(Template template,
636                         ICompilationUnit compilationUnit, int position)
637                         throws CoreException, BadLocationException, TemplateException {
638
639                 TemplateContextType contextType = WebUI.getDefault()
640                                 .getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
641                 if (contextType == null)
642                         throw new CoreException(
643                                         new Status(
644                                                         IStatus.ERROR,
645                                                         PHPeclipsePlugin.PLUGIN_ID,
646                                                         IStatus.ERROR,
647                                                         JavaTemplateMessages
648                                                                         .getString("JavaContext.error.message"), null)); //$NON-NLS-1$
649
650                 IDocument document = new Document();
651                 if (compilationUnit != null && compilationUnit.exists())
652                         document.set(compilationUnit.getSource());
653
654                 JavaContext context = new JavaContext(contextType, document, position,
655                                 0, compilationUnit);
656                 context.setForceEvaluation(true);
657
658                 TemplateBuffer buffer = context.evaluate(template);
659                 if (buffer == null)
660                         return null;
661                 return buffer.getString();
662         }
663
664 }