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();