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  *******************************************************************************/
 
  12 package net.sourceforge.phpdt.internal.ui.text.phpdoc;
 
  15 import java.text.BreakIterator;
 
  17 import net.sourceforge.phpdt.core.ICompilationUnit;
 
  18 import net.sourceforge.phpdt.core.IJavaElement;
 
  19 import net.sourceforge.phpdt.core.IMethod;
 
  20 import net.sourceforge.phpdt.core.ISourceRange;
 
  21 import net.sourceforge.phpdt.core.IType;
 
  22 import net.sourceforge.phpdt.internal.corext.util.Strings;
 
  23 import net.sourceforge.phpdt.ui.CodeGeneration;
 
  24 import net.sourceforge.phpdt.ui.IWorkingCopyManager;
 
  25 import net.sourceforge.phpdt.ui.PreferenceConstants;
 
  26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  28 import org.eclipse.core.runtime.CoreException;
 
  29 import org.eclipse.core.runtime.Preferences;
 
  30 import org.eclipse.jface.preference.IPreferenceStore;
 
  31 import org.eclipse.jface.text.BadLocationException;
 
  32 import org.eclipse.jface.text.DefaultAutoIndentStrategy;
 
  33 import org.eclipse.jface.text.DocumentCommand;
 
  34 import org.eclipse.jface.text.IDocument;
 
  35 import org.eclipse.jface.text.IRegion;
 
  36 import org.eclipse.jface.text.ITypedRegion;
 
  37 import org.eclipse.jface.text.TextUtilities;
 
  38 import org.eclipse.ui.IEditorPart;
 
  39 import org.eclipse.ui.IWorkbenchPage;
 
  40 import org.eclipse.ui.IWorkbenchWindow;
 
  41 import org.eclipse.ui.PlatformUI;
 
  42 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
 
  43 import org.eclipse.ui.texteditor.ITextEditorExtension3;
 
  47  * Auto indent strategy for java doc comments
 
  49 public class JavaDocAutoIndentStrategy extends DefaultAutoIndentStrategy {
 
  51         private String fPartitioning;
 
  54          * Creates a new Javadoc auto indent strategy for the given document partitioning.
 
  56          * @param partitioning the document partitioning
 
  58         public JavaDocAutoIndentStrategy(String partitioning) {
 
  59                 fPartitioning= partitioning;
 
  62         private static String getLineDelimiter(IDocument document) {
 
  64                         if (document.getNumberOfLines() > 1)
 
  65                                 return document.getLineDelimiter(0);
 
  66                 } catch (BadLocationException e) {
 
  67                   PHPeclipsePlugin.log(e);
 
  70                 return System.getProperty("line.separator"); //$NON-NLS-1$
 
  74          * Copies the indentation of the previous line and add a star.
 
  75          * If the javadoc just started on this line add standard method tags
 
  76          * and close the javadoc.
 
  78          * @param d the document to work on
 
  79          * @param c the command to deal with
 
  81         private void jdocIndentAfterNewLine(IDocument d, DocumentCommand c) {
 
  83                 if (c.offset == -1 || d.getLength() == 0)
 
  88                         int p= (c.offset == d.getLength() ? c.offset  - 1 : c.offset);
 
  89                         IRegion info= d.getLineInformationOfOffset(p);
 
  90                         int start= info.getOffset();
 
  93                         int end= findEndOfWhiteSpace(d, start, c.offset);
 
  95                         StringBuffer buf= new StringBuffer(c.text);
 
  96                         if (end >= start) {     // 1GEYL1R: ITPJUI:ALL - java doc edit smartness not work for class comments
 
  98                                 String indentation= jdocExtractLinePrefix(d, d.getLineOfOffset(c.offset));
 
  99                                 buf.append(indentation);
 
 100                                 if (end < c.offset) {
 
 101                                         if (d.getChar(end) == '/') {
 
 102                                                 // javadoc started on this line
 
 103                                                 buf.append(" * "); //$NON-NLS-1$
 
 105                                                 if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CLOSE_JAVADOCS) && isNewComment(d, c.offset, fPartitioning)) {
 
 106                                                         String lineDelimiter= getLineDelimiter(d);
 
 108                                                         String endTag= lineDelimiter + indentation + " */"; //$NON-NLS-1$
 
 109                                                         d.replace(c.offset, 0, endTag); //$NON-NLS-1$
 
 110                                                         // evaluate method signature
 
 111                                                         ICompilationUnit unit= getCompilationUnit();
 
 113 //                                                      if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS) &&
 
 117 //                                                                      JavaModelUtil.reconcile(unit);
 
 118 //                                                                      String string= createJavaDocTags(d, c, indentation, lineDelimiter, unit);
 
 119 //                                                                      if (string != null) {
 
 120 //                                                                              d.replace(c.offset, 0, string);
 
 122 //                                                              } catch (CoreException e) {
 
 132                         c.text= buf.toString();
 
 134                 } catch (BadLocationException excp) {
 
 139         private String createJavaDocTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, ICompilationUnit unit)
 
 140                 throws CoreException, BadLocationException
 
 142                 IJavaElement element= unit.getElementAt(command.offset);
 
 146                 switch (element.getElementType()) {
 
 147                 case IJavaElement.TYPE:
 
 148                         return createTypeTags(document, command, indentation, lineDelimiter, (IType) element);  
 
 150                 case IJavaElement.METHOD:
 
 151                         return createMethodTags(document, command, indentation, lineDelimiter, (IMethod) element);
 
 159          * Removes start and end of a comment and corrects indentation and line delimiters.
 
 161         private String prepareTemplateComment(String comment, String indentation, String lineDelimiter) {
 
 162                 //      trim comment start and end if any
 
 163                 if (comment.endsWith("*/")) //$NON-NLS-1$
 
 164                         comment= comment.substring(0, comment.length() - 2);
 
 165                 comment= comment.trim();
 
 166                 if (comment.startsWith("/*")) { //$NON-NLS-1$
 
 167                         if (comment.length() > 2 && comment.charAt(2) == '*') {
 
 168                                 comment= comment.substring(3); // remove '/**'
 
 170                                 comment= comment.substring(2); // remove '/*'
 
 173 //              return Strings.changeIndent(comment, 0, CodeFormatterUtil.getTabWidth(), indentation, lineDelimiter);
 
 174                 return Strings.changeIndent(comment, 0, getTabWidth(), indentation, lineDelimiter);
 
 177         public static int getTabWidth() {
 
 178                 Preferences preferences= PHPeclipsePlugin.getDefault().getPluginPreferences();
 
 179                 return preferences.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
 
 182         private String createTypeTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IType type)
 
 185                 String comment= CodeGeneration.getTypeComment(type.getCompilationUnit(), type.getTypeQualifiedName('.'), lineDelimiter);
 
 186                 if (comment != null) {
 
 187                         return prepareTemplateComment(comment.trim(), indentation, lineDelimiter);
 
 192         private String createMethodTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IMethod method)
 
 193                 throws CoreException, BadLocationException
 
 195                 IRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset, false);
 
 196                 ISourceRange sourceRange= method.getSourceRange();
 
 197                 if (sourceRange == null || sourceRange.getOffset() != partition.getOffset())
 
 200 //              IMethod inheritedMethod= getInheritedMethod(method);
 
 201 //              String comment= CodeGeneration.getMethodComment(method, inheritedMethod, lineDelimiter);
 
 202 //              if (comment != null) {
 
 203 //                      comment= comment.trim();
 
 204 //                      boolean javadocComment= comment.startsWith("/**"); //$NON-NLS-1$
 
 205 //                      boolean isJavaDoc= partition.getLength() >= 3 && document.get(partition.getOffset(), 3).equals("/**"); //$NON-NLS-1$
 
 206 //                      if (javadocComment == isJavaDoc) {
 
 207 //                              return prepareTemplateComment(comment, indentation, lineDelimiter);
 
 214          * Returns the method inherited from, <code>null</code> if method is newly defined.
 
 216 //      private static IMethod getInheritedMethod(IMethod method) throws JavaModelException {
 
 217 //              IType declaringType= method.getDeclaringType();
 
 218 //              ITypeHierarchy typeHierarchy= SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
 
 219 //              return JavaModelUtil.findMethodDeclarationInHierarchy(typeHierarchy, declaringType,
 
 220 //                      method.getElementName(), method.getParameterTypes(), method.isConstructor());
 
 223         protected void jdocIndentForCommentEnd(IDocument d, DocumentCommand c) {
 
 224                 if (c.offset < 2 || d.getLength() == 0) {
 
 228                         if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
 
 229                                 // modify document command
 
 233                 } catch (BadLocationException excp) {
 
 239          * Guesses if the command operates within a newly created javadoc comment or not.
 
 240          * If in doubt, it will assume that the javadoc is new.
 
 242         private static boolean isNewComment(IDocument document, int commandOffset, String partitioning) {
 
 245                         int lineIndex= document.getLineOfOffset(commandOffset) + 1;
 
 246                         if (lineIndex >= document.getNumberOfLines())
 
 249                         IRegion line= document.getLineInformation(lineIndex);
 
 250                         ITypedRegion partition= TextUtilities.getPartition(document, partitioning, commandOffset, false);
 
 251                         int partitionEnd= partition.getOffset() + partition.getLength();
 
 252                         if (line.getOffset() >= partitionEnd)
 
 255                         if (document.getLength() == partitionEnd)
 
 256                                 return true; // partition goes to end of document - probably a new comment
 
 258                         String comment= document.get(partition.getOffset(), partition.getLength());
 
 259                         if (comment.indexOf("/*", 2) != -1) //$NON-NLS-1$
 
 260                                 return true; // enclosed another comment -> probably a new comment
 
 264                 } catch (BadLocationException e) {
 
 269         private boolean isSmartMode() {
 
 270                 IWorkbenchPage page= PHPeclipsePlugin.getActivePage();
 
 272                         IEditorPart part= page.getActiveEditor(); 
 
 273                         if (part instanceof ITextEditorExtension3) {
 
 274                                 ITextEditorExtension3 extension= (ITextEditorExtension3) part;
 
 275                                 return extension.getInsertMode() == ITextEditorExtension3.SMART_INSERT;
 
 282          * @see IAutoIndentStrategy#customizeDocumentCommand
 
 284         public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
 
 291                         if (command.text != null && command.length == 0) {
 
 292                                 String[] lineDelimiters= document.getLegalLineDelimiters();
 
 293                                 int index= TextUtilities.endsWith(lineDelimiters, command.text);
 
 295                                         // ends with line delimiter
 
 296                                         if (lineDelimiters[index].equals(command.text))
 
 297                                                 // just the line delimiter
 
 298                                                 jdocIndentAfterNewLine(document, command);
 
 303                         if (command.text != null && command.text.equals("/")) { //$NON-NLS-1$
 
 304                                 jdocIndentForCommentEnd(document, command);
 
 308                         ITypedRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset, true);
 
 309                         int partitionStart= partition.getOffset();
 
 310                         int partitionEnd= partition.getLength() + partitionStart;                       
 
 312                         String text= command.text;
 
 313                         int offset= command.offset;
 
 314                         int length= command.length;
 
 317                         final int PREFIX_LENGTH= "/*".length(); //$NON-NLS-1$
 
 318                         final int POSTFIX_LENGTH= "*/".length(); //$NON-NLS-1$
 
 319                         if ((offset < partitionStart + PREFIX_LENGTH || offset + length > partitionEnd - POSTFIX_LENGTH) ||
 
 320                                 text != null && text.length() >= 2 && ((text.indexOf("*/") != -1) || (document.getChar(offset) == '*' && text.startsWith("/")))) //$NON-NLS-1$ //$NON-NLS-2$
 
 323                         if (command.text == null || command.text.length() == 0)
 
 324                                 jdocHandleBackspaceDelete(document, command);
 
 326                         else if (command.text != null && command.length == 0 && command.text.length() > 0)
 
 327                                 jdocWrapParagraphOnInsert(document, command);
 
 329                 } catch (BadLocationException e) {
 
 330                   PHPeclipsePlugin.log(e);
 
 334         private void flushCommand(IDocument document, DocumentCommand command) throws BadLocationException {
 
 339                 document.replace(command.offset, command.length, command.text);
 
 342                 if (command.text != null)
 
 343                         command.offset += command.text.length();
 
 348         protected void jdocWrapParagraphOnInsert(IDocument document, DocumentCommand command) throws BadLocationException {
 
 350 //              Assert.isTrue(command.length == 0);
 
 351 //              Assert.isTrue(command.text != null && command.text.length() == 1);
 
 353                 if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
 
 356                 int line= document.getLineOfOffset(command.offset);
 
 357                 IRegion region= document.getLineInformation(line);
 
 358                 int lineOffset= region.getOffset();
 
 359                 int lineLength= region.getLength();
 
 361                 String lineContents= document.get(lineOffset, lineLength);                                              
 
 362                 StringBuffer buffer= new StringBuffer(lineContents);
 
 363                 int start= command.offset - lineOffset;
 
 364                 int end= command.length + start; 
 
 365                 buffer.replace(start, end, command.text);
 
 368                 if (command.text != null && command.text.length() != 0 && command.text.trim().length() == 0) {
 
 370                         String endOfLine= document.get(command.offset, lineOffset + lineLength - command.offset);
 
 373                         if (endOfLine.length() == 0) {
 
 374                                 // move caret to next line
 
 375                                 flushCommand(document, command);
 
 377                                 if (isLineTooShort(document, line)) { 
 
 378                                         int[] caretOffset= {command.offset};
 
 379                                         jdocWrapParagraphFromLine(document, line, caretOffset, false);
 
 380                                         command.offset= caretOffset[0];
 
 384                                 // move caret to next line if possible
 
 385                                 if (line < document.getNumberOfLines() - 1 && isJavaDocLine(document, line + 1)) {
 
 386                                         String lineDelimiter= document.getLineDelimiter(line);
 
 387                                         String nextLinePrefix= jdocExtractLinePrefix(document, line + 1);
 
 388                                         command.offset += lineDelimiter.length() + nextLinePrefix.length();
 
 392                         // inside whitespace at end of line
 
 393                         } else if (endOfLine.trim().length() == 0) {
 
 394                                 // simply insert space
 
 399                 // change in prefix region
 
 400                 String prefix= jdocExtractLinePrefix(document, line);
 
 401                 boolean wrapAlways=     command.offset >= lineOffset && command.offset <= lineOffset + prefix.length();
 
 403                 // must insert the text now because it may include whitepace
 
 404                 flushCommand(document, command);                
 
 406                 if (wrapAlways || calculateDisplayedWidth(buffer.toString()) > getMargin() || isLineTooShort(document, line)) {
 
 407                         int[] caretOffset= {command.offset};                                                            
 
 408                         jdocWrapParagraphFromLine(document, line, caretOffset, wrapAlways);
 
 411                                 command.offset= caretOffset[0];
 
 416          * Method jdocWrapParagraphFromLine.
 
 422         private void jdocWrapParagraphFromLine(IDocument document, int line, int[] caretOffset, boolean always) throws BadLocationException {
 
 424                 String indent= jdocExtractLinePrefix(document, line);
 
 426                         if (!indent.trim().startsWith("*")) //$NON-NLS-1$
 
 429                         if (indent.trim().startsWith("*/")) //$NON-NLS-1$
 
 432                         if (!isLineTooLong(document, line) && !isLineTooShort(document, line))
 
 436                 boolean caretRelativeToParagraphOffset= false;
 
 437                 int caret= caretOffset[0];
 
 439                 int caretLine= document.getLineOfOffset(caret);
 
 440                 int lineOffset= document.getLineOffset(line);
 
 441                 int paragraphOffset= lineOffset + indent.length();
 
 442                 if (paragraphOffset < caret) {
 
 443                         caret -= paragraphOffset;
 
 444                         caretRelativeToParagraphOffset= true;
 
 449                 StringBuffer buffer= new StringBuffer();
 
 450                 int currentLine= line;
 
 451                 while (line == currentLine || isJavaDocLine(document, currentLine)) {
 
 453                         if (buffer.length() != 0 && !Character.isWhitespace(buffer.charAt(buffer.length() - 1))) {
 
 455                                 if (currentLine <= caretLine) {
 
 456                                         // in this case caretRelativeToParagraphOffset is always true
 
 461                         String string= getLineContents(document, currentLine);                  
 
 462                         buffer.append(string);
 
 465                 String paragraph= buffer.toString();
 
 467                 if (paragraph.trim().length() == 0)
 
 470                 caretOffset[0]= caretRelativeToParagraphOffset ? caret : 0;
 
 471                 String delimiter= document.getLineDelimiter(0);
 
 472                 String wrapped= formatParagraph(paragraph, caretOffset, indent, delimiter, getMargin());
 
 474                 int beginning= document.getLineOffset(line);
 
 475                 int end= document.getLineOffset(currentLine);
 
 476                 document.replace(beginning, end - beginning, wrapped.toString());
 
 478                 caretOffset[0]= caretRelativeToParagraphOffset ? caretOffset[0] + beginning : caret + beginning;
 
 482          * Line break iterator to handle whitespaces as first class citizens. 
 
 484         private static class LineBreakIterator {
 
 486                 private final String fString;
 
 487                 private final BreakIterator fIterator= BreakIterator.getLineInstance();
 
 491                 private int fBufferedEnd;
 
 493                 public LineBreakIterator(String string) {
 
 495                         fIterator.setText(string);
 
 500                         fStart= fIterator.first();
 
 506                         if (fBufferedEnd != -1) {
 
 514                         fEnd= fIterator.next();
 
 516                         if (fEnd == BreakIterator.DONE)
 
 519                         final String string= fString.substring(fStart, fEnd);
 
 522                         if (string.trim().length() == 0)
 
 525                         final String word= string.trim();
 
 526                         if (word.length() == string.length())
 
 529                         // suspected whitespace
 
 531                         return fStart + word.length();
 
 536          * Formats a paragraph, using break iterator.  
 
 538          * @param offset an offset within the paragraph, which will be updated with respect to formatting.
 
 540         private static String formatParagraph(String paragraph, int[] offset, String prefix, String lineDelimiter, int margin) {
 
 542                 LineBreakIterator iterator= new LineBreakIterator(paragraph);
 
 544                 StringBuffer paragraphBuffer= new StringBuffer();
 
 545                 StringBuffer lineBuffer= new StringBuffer();
 
 546                 StringBuffer whiteSpaceBuffer= new StringBuffer();
 
 548                 int index= offset[0];
 
 551          // line delimiter could be null
 
 552         if (lineDelimiter == null)
 
 553             lineDelimiter= ""; //$NON-NLS-1$
 
 555                 for (int start= iterator.first(), end= iterator.next(); end != BreakIterator.DONE; start= end, end= iterator.next()) {
 
 557                         String word= paragraph.substring(start, end);
 
 559                         // word is whitespace
 
 560                         if (word.trim().length() == 0) {
 
 561                                 whiteSpaceBuffer.append(word);
 
 563                         // first word of line is always appended                        
 
 564                         } else if (lineBuffer.length() == 0) {
 
 565                                 lineBuffer.append(prefix);
 
 566                                 lineBuffer.append(whiteSpaceBuffer.toString());
 
 567                                 lineBuffer.append(word);
 
 570                                 String line= lineBuffer.toString() + whiteSpaceBuffer.toString()  + word.toString();
 
 573                                 if (calculateDisplayedWidth(line) > margin) {
 
 574                                         // flush line buffer and wrap paragraph
 
 575                                         paragraphBuffer.append(lineBuffer.toString());
 
 576                                         paragraphBuffer.append(lineDelimiter);
 
 577                                         lineBuffer.setLength(0);
 
 578                                         lineBuffer.append(prefix);
 
 579                                         lineBuffer.append(word);
 
 581                                         // flush index buffer
 
 582                                         if (indexBuffer != -1) {
 
 583                                                 offset[0]= indexBuffer;
 
 584                                                 // correct for caret in whitespace at the end of line
 
 585                                                 if (whiteSpaceBuffer.length() != 0 && index < start && index >= start - whiteSpaceBuffer.length())
 
 586                                                         offset[0] -= (index - (start - whiteSpaceBuffer.length()));
 
 590                                         whiteSpaceBuffer.setLength(0);
 
 592                                 // margin not exceeded
 
 594                                         lineBuffer.append(whiteSpaceBuffer.toString());
 
 595                                         lineBuffer.append(word);
 
 596                                         whiteSpaceBuffer.setLength(0);
 
 600                         if (index >= start && index < end) {
 
 601                                 indexBuffer= paragraphBuffer.length() + lineBuffer.length() + (index - start);
 
 602                                 if (word.trim().length() != 0)
 
 603                                         indexBuffer -= word.length();
 
 608                 paragraphBuffer.append(lineBuffer.toString());
 
 609                 paragraphBuffer.append(lineDelimiter);
 
 611                 // flush index buffer
 
 612                 if (indexBuffer != -1)  
 
 613                         offset[0]= indexBuffer;
 
 615                 // last position is not returned by break iterator
 
 616                 else if (offset[0] == paragraph.length())
 
 617                         offset[0]= paragraphBuffer.length() - lineDelimiter.length();
 
 619                 return paragraphBuffer.toString();
 
 622         private static IPreferenceStore getPreferenceStore() {
 
 623                 return PHPeclipsePlugin.getDefault().getPreferenceStore();              
 
 627          * Returns the displayed width of a string, taking in account the displayed tab width.
 
 628          * The result can be compared against the print margin.
 
 630         private static int calculateDisplayedWidth(String string) {
 
 632                 int tabWidth= getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); 
 
 637                 for (int i= 0; i < string.length(); i++)
 
 638                         if ('\t' == string.charAt(i))
 
 639                                 column += tabWidth - (column % tabWidth);
 
 646         private String jdocExtractLinePrefix(IDocument d, int line) throws BadLocationException {
 
 648                 IRegion region= d.getLineInformation(line);
 
 649                 int lineOffset= region.getOffset();
 
 650                 int index= findEndOfWhiteSpace(d, lineOffset, lineOffset + d.getLineLength(line));
 
 651                 if (d.getChar(index) == '*') {
 
 653                         if (index != lineOffset + region.getLength() &&d.getChar(index) == ' ')
 
 656                 return d.get(lineOffset, index - lineOffset);
 
 659         private String getLineContents(IDocument d, int line) throws BadLocationException {
 
 660                 int offset = d.getLineOffset(line);
 
 661                 int length = d.getLineLength(line);
 
 662         String lineDelimiter= d.getLineDelimiter(line);
 
 663         if (lineDelimiter != null)
 
 664             length= length - lineDelimiter.length();
 
 665                 String lineContents = d.get(offset, length);
 
 666                 int trim = jdocExtractLinePrefix(d, line).length();
 
 667                 return lineContents.substring(trim);
 
 670         private static String getLine(IDocument document, int line) throws BadLocationException {
 
 671                 IRegion region= document.getLineInformation(line);              
 
 672                 return document.get(region.getOffset(), region.getLength());            
 
 676          * Returns <code>true</code> if the javadoc line is too short, <code>false</code> otherwise.
 
 678         private boolean isLineTooShort(IDocument document, int line) throws BadLocationException {
 
 680                 if (!isJavaDocLine(document, line + 1))
 
 683                 String nextLine= getLineContents(document, line + 1);
 
 684                 if (nextLine.trim().length() == 0)
 
 691          * Returns <code>true</code> if the line is too long, <code>false</code> otherwise.
 
 693         private boolean isLineTooLong(IDocument document, int line) throws BadLocationException {
 
 694                 String lineContents= getLine(document, line);
 
 695                 return calculateDisplayedWidth(lineContents) > getMargin();
 
 698         private static int getMargin() {
 
 699                 return getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN);
 
 702         private static final String[] fgInlineTags= {
 
 703                 "<b>", "<i>", "<em>", "<strong>", "<code>"  //$NON-NLS-1$  //$NON-NLS-2$  //$NON-NLS-3$  //$NON-NLS-4$ //$NON-NLS-5$
 
 706         private boolean isInlineTag(String string) {
 
 707                 for (int i= 0; i < fgInlineTags.length; i++)
 
 708                         if (string.startsWith(fgInlineTags[i]))
 
 714          * returns true if the specified line is part of a paragraph and should be merged with
 
 717         private boolean isJavaDocLine(IDocument document, int line) throws BadLocationException {
 
 719                 if (document.getNumberOfLines() < line)
 
 722                 int offset= document.getLineOffset(line);
 
 723                 int length= document.getLineLength(line);
 
 724                 int firstChar= findEndOfWhiteSpace(document, offset, offset + length);
 
 725                 length -= firstChar - offset;
 
 726                 String lineContents= document.get(firstChar, length);
 
 728                 String prefix= lineContents.trim();             
 
 729                 if (!prefix.startsWith("*") || prefix.startsWith("*/")) //$NON-NLS-1$ //$NON-NLS-2$
 
 732                 lineContents= lineContents.substring(1).trim().toLowerCase();
 
 734                 // preserve empty lines
 
 735                 if (lineContents.length() == 0)
 
 739                 if (lineContents.startsWith("@")) //$NON-NLS-1$
 
 742                 // preserve HTML tags which are not inline
 
 743                 if (lineContents.startsWith("<") && !isInlineTag(lineContents)) //$NON-NLS-1$
 
 749         protected void jdocHandleBackspaceDelete(IDocument document, DocumentCommand c) {
 
 751                 if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
 
 755                         String text= document.get(c.offset, c.length);
 
 756                         int line= document.getLineOfOffset(c.offset);
 
 757                         int lineOffset= document.getLineOffset(line);
 
 759                         // erase line delimiter
 
 760                         String lineDelimiter= document.getLineDelimiter(line);
 
 761                         if (lineDelimiter != null && lineDelimiter.equals(text)) {
 
 763                                 String prefix= jdocExtractLinePrefix(document, line + 1);
 
 765                                 // strip prefix if any
 
 766                                 if (prefix.length() > 0) {
 
 767                                         int length= document.getLineDelimiter(line).length() + prefix.length();
 
 768                                         document.replace(c.offset, length, null);
 
 775                         // backspace: beginning of a javadoc line
 
 776                         } else if (document.getChar(c.offset - 1) == '*' && jdocExtractLinePrefix(document, line).length() - 1 >= c.offset - lineOffset) {
 
 778                                 lineDelimiter= document.getLineDelimiter(line - 1);
 
 779                                 String prefix= jdocExtractLinePrefix(document, line);
 
 780                                 int length= (lineDelimiter != null ? lineDelimiter.length() : 0) + prefix.length();
 
 781                                 document.replace(c.offset - length + 1, length, null);
 
 784                                 c.offset -= length - 1;
 
 789                                 document.replace(c.offset, c.length, null);
 
 794                 } catch (BadLocationException e) {
 
 795                   PHPeclipsePlugin.log(e);
 
 799                         int line= document.getLineOfOffset(c.offset);
 
 800                         int lineOffset= document.getLineOffset(line);
 
 801                         String prefix= jdocExtractLinePrefix(document, line);
 
 802                         boolean always= c.offset > lineOffset && c.offset <= lineOffset + prefix.length();
 
 803                         int[] caretOffset= {c.offset};
 
 804                         jdocWrapParagraphFromLine(document, document.getLineOfOffset(c.offset), caretOffset, always);
 
 805                         c.offset= caretOffset[0];
 
 807                 } catch (BadLocationException e) {
 
 808                   PHPeclipsePlugin.log(e);
 
 813          * Returns the compilation unit of the CompilationUnitEditor invoking the AutoIndentStrategy,
 
 814          * might return <code>null</code> on error.
 
 816         private static ICompilationUnit getCompilationUnit() {
 
 818                 IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
 
 822                 IWorkbenchPage page= window.getActivePage();
 
 826                 IEditorPart editor= page.getActiveEditor();
 
 830                 IWorkingCopyManager manager= PHPeclipsePlugin.getDefault().getWorkingCopyManager();
 
 831                 ICompilationUnit unit= manager.getWorkingCopy(editor.getEditorInput());