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;
 
  14 import java.text.BreakIterator;
 
  16 import net.sourceforge.phpdt.core.ICompilationUnit;
 
  17 //import net.sourceforge.phpdt.core.IJavaElement;
 
  18 import net.sourceforge.phpdt.core.IMethod;
 
  19 import net.sourceforge.phpdt.core.ISourceRange;
 
  20 import net.sourceforge.phpdt.core.IType;
 
  21 import net.sourceforge.phpdt.internal.corext.util.Strings;
 
  22 import net.sourceforge.phpdt.ui.CodeGeneration;
 
  23 import net.sourceforge.phpdt.ui.IWorkingCopyManager;
 
  24 import net.sourceforge.phpdt.ui.PreferenceConstants;
 
  25 //import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  26 import net.sourceforge.phpeclipse.ui.WebUI;
 
  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.DefaultIndentLineAutoEditStrategy;
 
  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;
 
  46  * Auto indent strategy for java doc comments
 
  48 public class JavaDocAutoIndentStrategy extends
 
  49                 DefaultIndentLineAutoEditStrategy {
 
  51         private String fPartitioning;
 
  54          * Creates a new Javadoc auto indent strategy for the given document
 
  58          *            the document partitioning
 
  60         public JavaDocAutoIndentStrategy(String partitioning) {
 
  61                 fPartitioning = partitioning;
 
  64         private static String getLineDelimiter(IDocument document) {
 
  66                         if (document.getNumberOfLines() > 1)
 
  67                                 return document.getLineDelimiter(0);
 
  68                 } catch (BadLocationException e) {
 
  72                 return System.getProperty("line.separator"); //$NON-NLS-1$
 
  76          * Copies the indentation of the previous line and add a star. If the
 
  77          * javadoc just started on this line add standard method tags and close the
 
  81          *            the document to work on
 
  83          *            the command to deal with
 
  85         private void jdocIndentAfterNewLine(IDocument d, DocumentCommand c) {
 
  87                 if (c.offset == -1 || d.getLength() == 0)
 
  92                         int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
 
  93                         IRegion info = d.getLineInformationOfOffset(p);
 
  94                         int start = info.getOffset();
 
  97                         int end = findEndOfWhiteSpace(d, start, c.offset);
 
  99                         StringBuffer buf = new StringBuffer(c.text);
 
 100                         if (end >= start) { // 1GEYL1R: ITPJUI:ALL - java doc edit smartness
 
 101                                                                 // not work for class comments
 
 103                                 String indentation = jdocExtractLinePrefix(d, d
 
 104                                                 .getLineOfOffset(c.offset));
 
 105                                 buf.append(indentation);
 
 106                                 if (end < c.offset) {
 
 107                                         if (d.getChar(end) == '/') {
 
 108                                                 // javadoc started on this line
 
 109                                                 buf.append(" * "); //$NON-NLS-1$
 
 113                                                                 .getPreferenceStore()
 
 115                                                                                 PreferenceConstants.EDITOR_CLOSE_JAVADOCS)
 
 116                                                                 && isNewComment(d, c.offset, fPartitioning)) {
 
 117                                                         String lineDelimiter = getLineDelimiter(d);
 
 119                                                         String endTag = lineDelimiter + indentation + " */"; //$NON-NLS-1$
 
 120                                                         d.replace(c.offset, 0, endTag); //$NON-NLS-1$
 
 121                                                         // evaluate method signature
 
 122                                                         //ICompilationUnit unit = getCompilationUnit();
 
 125                                                         // (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS)
 
 130                                                         // JavaModelUtil.reconcile(unit);
 
 131                                                         // String string= createJavaDocTags(d, c,
 
 132                                                         // indentation, lineDelimiter, unit);
 
 133                                                         // if (string != null) {
 
 134                                                         // d.replace(c.offset, 0, string);
 
 136                                                         // } catch (CoreException e) {
 
 146                         c.text = buf.toString();
 
 148                 } catch (BadLocationException excp) {
 
 153 //      private String createJavaDocTags(IDocument document,
 
 154 //                      DocumentCommand command, String indentation, String lineDelimiter,
 
 155 //                      ICompilationUnit unit) throws CoreException, BadLocationException {
 
 156 //              IJavaElement element = unit.getElementAt(command.offset);
 
 157 //              if (element == null)
 
 160 //              switch (element.getElementType()) {
 
 161 //              case IJavaElement.TYPE:
 
 162 //                      return createTypeTags(document, command, indentation,
 
 163 //                                      lineDelimiter, (IType) element);
 
 165 //              case IJavaElement.METHOD:
 
 166 //                      return createMethodTags(document, command, indentation,
 
 167 //                                      lineDelimiter, (IMethod) element);
 
 175          * Removes start and end of a comment and corrects indentation and line
 
 178         private String prepareTemplateComment(String comment, String indentation,
 
 179                         String lineDelimiter) {
 
 180                 // trim comment start and end if any
 
 181                 if (comment.endsWith("*/")) //$NON-NLS-1$
 
 182                         comment = comment.substring(0, comment.length() - 2);
 
 183                 comment = comment.trim();
 
 184                 if (comment.startsWith("/*")) { //$NON-NLS-1$
 
 185                         if (comment.length() > 2 && comment.charAt(2) == '*') {
 
 186                                 comment = comment.substring(3); // remove '/**'
 
 188                                 comment = comment.substring(2); // remove '/*'
 
 191                 // return Strings.changeIndent(comment, 0,
 
 192                 // CodeFormatterUtil.getTabWidth(), indentation, lineDelimiter);
 
 193                 return Strings.changeIndent(comment, 0, getTabWidth(), indentation,
 
 197         public static int getTabWidth() {
 
 198                 Preferences preferences = WebUI.getDefault()
 
 199                                 .getPluginPreferences();
 
 201                                 .getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
 
 204         private String createTypeTags(IDocument document, DocumentCommand command,
 
 205                         String indentation, String lineDelimiter, IType type)
 
 206                         throws CoreException {
 
 207                 String comment = CodeGeneration.getTypeComment(type
 
 208                                 .getCompilationUnit(), type.getTypeQualifiedName('.'),
 
 210                 if (comment != null) {
 
 211                         return prepareTemplateComment(comment.trim(), indentation,
 
 217         private String createMethodTags(IDocument document,
 
 218                         DocumentCommand command, String indentation, String lineDelimiter,
 
 219                         IMethod method) throws CoreException, BadLocationException {
 
 220                 IRegion partition = TextUtilities.getPartition(document, fPartitioning,
 
 221                                 command.offset, false);
 
 222                 ISourceRange sourceRange = method.getSourceRange();
 
 223                 if (sourceRange == null
 
 224                                 || sourceRange.getOffset() != partition.getOffset())
 
 227                 // IMethod inheritedMethod= getInheritedMethod(method);
 
 228                 // String comment= CodeGeneration.getMethodComment(method,
 
 229                 // inheritedMethod, lineDelimiter);
 
 230                 // if (comment != null) {
 
 231                 // comment= comment.trim();
 
 232                 // boolean javadocComment= comment.startsWith("/**"); //$NON-NLS-1$
 
 233                 // boolean isJavaDoc= partition.getLength() >= 3 &&
 
 234                 // document.get(partition.getOffset(), 3).equals("/**"); //$NON-NLS-1$
 
 235                 // if (javadocComment == isJavaDoc) {
 
 236                 // return prepareTemplateComment(comment, indentation, lineDelimiter);
 
 243          * Returns the method inherited from, <code>null</code> if method is newly
 
 246         // private static IMethod getInheritedMethod(IMethod method) throws
 
 247         // JavaModelException {
 
 248         // IType declaringType= method.getDeclaringType();
 
 249         // ITypeHierarchy typeHierarchy=
 
 250         // SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
 
 251         // return JavaModelUtil.findMethodDeclarationInHierarchy(typeHierarchy,
 
 253         // method.getElementName(), method.getParameterTypes(),
 
 254         // method.isConstructor());
 
 256         protected void jdocIndentForCommentEnd(IDocument d, DocumentCommand c) {
 
 257                 if (c.offset < 2 || d.getLength() == 0) {
 
 261                         if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
 
 262                                 // modify document command
 
 266                 } catch (BadLocationException excp) {
 
 272          * Guesses if the command operates within a newly created javadoc comment or
 
 273          * not. If in doubt, it will assume that the javadoc is new.
 
 275         private static boolean isNewComment(IDocument document, int commandOffset,
 
 276                         String partitioning) {
 
 279                         int lineIndex = document.getLineOfOffset(commandOffset) + 1;
 
 280                         if (lineIndex >= document.getNumberOfLines())
 
 283                         IRegion line = document.getLineInformation(lineIndex);
 
 284                         ITypedRegion partition = TextUtilities.getPartition(document,
 
 285                                         partitioning, commandOffset, false);
 
 286                         int partitionEnd = partition.getOffset() + partition.getLength();
 
 287                         if (line.getOffset() >= partitionEnd)
 
 290                         if (document.getLength() == partitionEnd)
 
 291                                 return true; // partition goes to end of document - probably
 
 294                         String comment = document.get(partition.getOffset(), partition
 
 296                         if (comment.indexOf("/*", 2) != -1) //$NON-NLS-1$
 
 297                                 return true; // enclosed another comment -> probably a new
 
 302                 } catch (BadLocationException e) {
 
 307         private boolean isSmartMode() {
 
 308                 IWorkbenchPage page = WebUI.getActivePage();
 
 310                         IEditorPart part = page.getActiveEditor();
 
 311                         if (part instanceof ITextEditorExtension3) {
 
 312                                 ITextEditorExtension3 extension = (ITextEditorExtension3) part;
 
 313                                 return extension.getInsertMode() == ITextEditorExtension3.SMART_INSERT;
 
 320          * @see IAutoIndentStrategy#customizeDocumentCommand
 
 322         public void customizeDocumentCommand(IDocument document,
 
 323                         DocumentCommand command) {
 
 330                         if (command.text != null && command.length == 0) {
 
 331                                 String[] lineDelimiters = document.getLegalLineDelimiters();
 
 332                                 int index = TextUtilities
 
 333                                                 .endsWith(lineDelimiters, command.text);
 
 335                                         // ends with line delimiter
 
 336                                         if (lineDelimiters[index].equals(command.text))
 
 337                                                 // just the line delimiter
 
 338                                                 jdocIndentAfterNewLine(document, command);
 
 343                         if (command.text != null && command.text.equals("/")) { //$NON-NLS-1$
 
 344                                 jdocIndentForCommentEnd(document, command);
 
 348                         ITypedRegion partition = TextUtilities.getPartition(document,
 
 349                                         fPartitioning, command.offset, true);
 
 350                         int partitionStart = partition.getOffset();
 
 351                         int partitionEnd = partition.getLength() + partitionStart;
 
 353                         String text = command.text;
 
 354                         int offset = command.offset;
 
 355                         int length = command.length;
 
 358                         final int PREFIX_LENGTH = "/*".length(); //$NON-NLS-1$
 
 359                         final int POSTFIX_LENGTH = "*/".length(); //$NON-NLS-1$
 
 360                         if ((offset < partitionStart + PREFIX_LENGTH || offset + length > partitionEnd
 
 363                                         && text.length() >= 2
 
 364                                         && ((text.indexOf("*/") != -1) || (document.getChar(offset) == '*' && text.startsWith("/")))) //$NON-NLS-1$ //$NON-NLS-2$
 
 367                         if (command.text == null || command.text.length() == 0)
 
 368                                 jdocHandleBackspaceDelete(document, command);
 
 370                         else if (command.text != null && command.length == 0
 
 371                                         && command.text.length() > 0)
 
 372                                 jdocWrapParagraphOnInsert(document, command);
 
 374                 } catch (BadLocationException e) {
 
 379         private void flushCommand(IDocument document, DocumentCommand command)
 
 380                         throws BadLocationException {
 
 385                 document.replace(command.offset, command.length, command.text);
 
 387                 command.doit = false;
 
 388                 if (command.text != null)
 
 389                         command.offset += command.text.length();
 
 394         protected void jdocWrapParagraphOnInsert(IDocument document,
 
 395                         DocumentCommand command) throws BadLocationException {
 
 397                 // Assert.isTrue(command.length == 0);
 
 398                 // Assert.isTrue(command.text != null && command.text.length() == 1);
 
 400                 if (!getPreferenceStore().getBoolean(
 
 401                                 PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
 
 404                 int line = document.getLineOfOffset(command.offset);
 
 405                 IRegion region = document.getLineInformation(line);
 
 406                 int lineOffset = region.getOffset();
 
 407                 int lineLength = region.getLength();
 
 409                 String lineContents = document.get(lineOffset, lineLength);
 
 410                 StringBuffer buffer = new StringBuffer(lineContents);
 
 411                 int start = command.offset - lineOffset;
 
 412                 int end = command.length + start;
 
 413                 buffer.replace(start, end, command.text);
 
 416                 if (command.text != null && command.text.length() != 0
 
 417                                 && command.text.trim().length() == 0) {
 
 419                         String endOfLine = document.get(command.offset, lineOffset
 
 420                                         + lineLength - command.offset);
 
 423                         if (endOfLine.length() == 0) {
 
 424                                 // move caret to next line
 
 425                                 flushCommand(document, command);
 
 427                                 if (isLineTooShort(document, line)) {
 
 428                                         int[] caretOffset = { command.offset };
 
 429                                         jdocWrapParagraphFromLine(document, line, caretOffset,
 
 431                                         command.offset = caretOffset[0];
 
 435                                 // move caret to next line if possible
 
 436                                 if (line < document.getNumberOfLines() - 1
 
 437                                                 && isJavaDocLine(document, line + 1)) {
 
 438                                         String lineDelimiter = document.getLineDelimiter(line);
 
 439                                         String nextLinePrefix = jdocExtractLinePrefix(document,
 
 441                                         command.offset += lineDelimiter.length()
 
 442                                                         + nextLinePrefix.length();
 
 446                                 // inside whitespace at end of line
 
 447                         } else if (endOfLine.trim().length() == 0) {
 
 448                                 // simply insert space
 
 453                 // change in prefix region
 
 454                 String prefix = jdocExtractLinePrefix(document, line);
 
 455                 boolean wrapAlways = command.offset >= lineOffset
 
 456                                 && command.offset <= lineOffset + prefix.length();
 
 458                 // must insert the text now because it may include whitepace
 
 459                 flushCommand(document, command);
 
 462                                 || calculateDisplayedWidth(buffer.toString()) > getMargin()
 
 463                                 || isLineTooShort(document, line)) {
 
 464                         int[] caretOffset = { command.offset };
 
 465                         jdocWrapParagraphFromLine(document, line, caretOffset, wrapAlways);
 
 468                                 command.offset = caretOffset[0];
 
 473          * Method jdocWrapParagraphFromLine.
 
 479         private void jdocWrapParagraphFromLine(IDocument document, int line,
 
 480                         int[] caretOffset, boolean always) throws BadLocationException {
 
 482                 String indent = jdocExtractLinePrefix(document, line);
 
 484                         if (!indent.trim().startsWith("*")) //$NON-NLS-1$
 
 487                         if (indent.trim().startsWith("*/")) //$NON-NLS-1$
 
 490                         if (!isLineTooLong(document, line)
 
 491                                         && !isLineTooShort(document, line))
 
 495                 boolean caretRelativeToParagraphOffset = false;
 
 496                 int caret = caretOffset[0];
 
 498                 int caretLine = document.getLineOfOffset(caret);
 
 499                 int lineOffset = document.getLineOffset(line);
 
 500                 int paragraphOffset = lineOffset + indent.length();
 
 501                 if (paragraphOffset < caret) {
 
 502                         caret -= paragraphOffset;
 
 503                         caretRelativeToParagraphOffset = true;
 
 508                 StringBuffer buffer = new StringBuffer();
 
 509                 int currentLine = line;
 
 510                 while (line == currentLine || isJavaDocLine(document, currentLine)) {
 
 512                         if (buffer.length() != 0
 
 513                                         && !Character.isWhitespace(buffer
 
 514                                                         .charAt(buffer.length() - 1))) {
 
 516                                 if (currentLine <= caretLine) {
 
 517                                         // in this case caretRelativeToParagraphOffset is always
 
 523                         String string = getLineContents(document, currentLine);
 
 524                         buffer.append(string);
 
 527                 String paragraph = buffer.toString();
 
 529                 if (paragraph.trim().length() == 0)
 
 532                 caretOffset[0] = caretRelativeToParagraphOffset ? caret : 0;
 
 533                 String delimiter = document.getLineDelimiter(0);
 
 534                 String wrapped = formatParagraph(paragraph, caretOffset, indent,
 
 535                                 delimiter, getMargin());
 
 537                 int beginning = document.getLineOffset(line);
 
 538                 int end = document.getLineOffset(currentLine);
 
 539                 document.replace(beginning, end - beginning, wrapped.toString());
 
 541                 caretOffset[0] = caretRelativeToParagraphOffset ? caretOffset[0]
 
 542                                 + beginning : caret + beginning;
 
 546          * Line break iterator to handle whitespaces as first class citizens.
 
 548         private static class LineBreakIterator {
 
 550                 private final String fString;
 
 552                 private final BreakIterator fIterator = BreakIterator.getLineInstance();
 
 558                 private int fBufferedEnd;
 
 560                 public LineBreakIterator(String string) {
 
 562                         fIterator.setText(string);
 
 567                         fStart = fIterator.first();
 
 573                         if (fBufferedEnd != -1) {
 
 581                         fEnd = fIterator.next();
 
 583                         if (fEnd == BreakIterator.DONE)
 
 586                         final String string = fString.substring(fStart, fEnd);
 
 589                         if (string.trim().length() == 0)
 
 592                         final String word = string.trim();
 
 593                         if (word.length() == string.length())
 
 596                         // suspected whitespace
 
 598                         return fStart + word.length();
 
 603          * Formats a paragraph, using break iterator.
 
 606          *            an offset within the paragraph, which will be updated with
 
 607          *            respect to formatting.
 
 609         private static String formatParagraph(String paragraph, int[] offset,
 
 610                         String prefix, String lineDelimiter, int margin) {
 
 612                 LineBreakIterator iterator = new LineBreakIterator(paragraph);
 
 614                 StringBuffer paragraphBuffer = new StringBuffer();
 
 615                 StringBuffer lineBuffer = new StringBuffer();
 
 616                 StringBuffer whiteSpaceBuffer = new StringBuffer();
 
 618                 int index = offset[0];
 
 619                 int indexBuffer = -1;
 
 621                 // line delimiter could be null
 
 622                 if (lineDelimiter == null)
 
 623                         lineDelimiter = ""; //$NON-NLS-1$
 
 625                 for (int start = iterator.first(), end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator
 
 628                         String word = paragraph.substring(start, end);
 
 630                         // word is whitespace
 
 631                         if (word.trim().length() == 0) {
 
 632                                 whiteSpaceBuffer.append(word);
 
 634                                 // first word of line is always appended
 
 635                         } else if (lineBuffer.length() == 0) {
 
 636                                 lineBuffer.append(prefix);
 
 637                                 lineBuffer.append(whiteSpaceBuffer.toString());
 
 638                                 lineBuffer.append(word);
 
 641                                 String line = lineBuffer.toString()
 
 642                                                 + whiteSpaceBuffer.toString() + word.toString();
 
 645                                 if (calculateDisplayedWidth(line) > margin) {
 
 646                                         // flush line buffer and wrap paragraph
 
 647                                         paragraphBuffer.append(lineBuffer.toString());
 
 648                                         paragraphBuffer.append(lineDelimiter);
 
 649                                         lineBuffer.setLength(0);
 
 650                                         lineBuffer.append(prefix);
 
 651                                         lineBuffer.append(word);
 
 653                                         // flush index buffer
 
 654                                         if (indexBuffer != -1) {
 
 655                                                 offset[0] = indexBuffer;
 
 656                                                 // correct for caret in whitespace at the end of line
 
 657                                                 if (whiteSpaceBuffer.length() != 0 && index < start
 
 658                                                                 && index >= start - whiteSpaceBuffer.length())
 
 659                                                         offset[0] -= (index - (start - whiteSpaceBuffer
 
 664                                         whiteSpaceBuffer.setLength(0);
 
 666                                         // margin not exceeded
 
 668                                         lineBuffer.append(whiteSpaceBuffer.toString());
 
 669                                         lineBuffer.append(word);
 
 670                                         whiteSpaceBuffer.setLength(0);
 
 674                         if (index >= start && index < end) {
 
 675                                 indexBuffer = paragraphBuffer.length() + lineBuffer.length()
 
 677                                 if (word.trim().length() != 0)
 
 678                                         indexBuffer -= word.length();
 
 683                 paragraphBuffer.append(lineBuffer.toString());
 
 684                 paragraphBuffer.append(lineDelimiter);
 
 686                 // flush index buffer
 
 687                 if (indexBuffer != -1)
 
 688                         offset[0] = indexBuffer;
 
 690                 // last position is not returned by break iterator
 
 691                 else if (offset[0] == paragraph.length())
 
 692                         offset[0] = paragraphBuffer.length() - lineDelimiter.length();
 
 694                 return paragraphBuffer.toString();
 
 697         private static IPreferenceStore getPreferenceStore() {
 
 698                 return WebUI.getDefault().getPreferenceStore();
 
 702          * Returns the displayed width of a string, taking in account the displayed
 
 703          * tab width. The result can be compared against the print margin.
 
 705         private static int calculateDisplayedWidth(String string) {
 
 707                 int tabWidth = getPreferenceStore()
 
 709                                                 AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
 
 714                 for (int i = 0; i < string.length(); i++)
 
 715                         if ('\t' == string.charAt(i))
 
 716                                 column += tabWidth - (column % tabWidth);
 
 723         private String jdocExtractLinePrefix(IDocument d, int line)
 
 724                         throws BadLocationException {
 
 726                 IRegion region = d.getLineInformation(line);
 
 727                 int lineOffset = region.getOffset();
 
 728                 int index = findEndOfWhiteSpace(d, lineOffset, lineOffset
 
 729                                 + d.getLineLength(line));
 
 730                 if (d.getChar(index) == '*') {
 
 732                         if (index != lineOffset + region.getLength()
 
 733                                         && d.getChar(index) == ' ')
 
 736                 return d.get(lineOffset, index - lineOffset);
 
 739         private String getLineContents(IDocument d, int line)
 
 740                         throws BadLocationException {
 
 741                 int offset = d.getLineOffset(line);
 
 742                 int length = d.getLineLength(line);
 
 743                 String lineDelimiter = d.getLineDelimiter(line);
 
 744                 if (lineDelimiter != null)
 
 745                         length = length - lineDelimiter.length();
 
 746                 String lineContents = d.get(offset, length);
 
 747                 int trim = jdocExtractLinePrefix(d, line).length();
 
 748                 return lineContents.substring(trim);
 
 751         private static String getLine(IDocument document, int line)
 
 752                         throws BadLocationException {
 
 753                 IRegion region = document.getLineInformation(line);
 
 754                 return document.get(region.getOffset(), region.getLength());
 
 758          * Returns <code>true</code> if the javadoc line is too short,
 
 759          * <code>false</code> otherwise.
 
 761         private boolean isLineTooShort(IDocument document, int line)
 
 762                         throws BadLocationException {
 
 764                 if (!isJavaDocLine(document, line + 1))
 
 767                 String nextLine = getLineContents(document, line + 1);
 
 768                 if (nextLine.trim().length() == 0)
 
 775          * Returns <code>true</code> if the line is too long, <code>false</code>
 
 778         private boolean isLineTooLong(IDocument document, int line)
 
 779                         throws BadLocationException {
 
 780                 String lineContents = getLine(document, line);
 
 781                 return calculateDisplayedWidth(lineContents) > getMargin();
 
 784         private static int getMargin() {
 
 785                 return getPreferenceStore()
 
 787                                                 AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN);
 
 790         private static final String[] fgInlineTags = {
 
 791                         "<b>", "<i>", "<em>", "<strong>", "<code>" //$NON-NLS-1$  //$NON-NLS-2$  //$NON-NLS-3$  //$NON-NLS-4$ //$NON-NLS-5$
 
 794         private boolean isInlineTag(String string) {
 
 795                 for (int i = 0; i < fgInlineTags.length; i++)
 
 796                         if (string.startsWith(fgInlineTags[i]))
 
 802          * returns true if the specified line is part of a paragraph and should be
 
 803          * merged with the previous line.
 
 805         private boolean isJavaDocLine(IDocument document, int line)
 
 806                         throws BadLocationException {
 
 808                 if (document.getNumberOfLines() < line)
 
 811                 int offset = document.getLineOffset(line);
 
 812                 int length = document.getLineLength(line);
 
 813                 int firstChar = findEndOfWhiteSpace(document, offset, offset + length);
 
 814                 length -= firstChar - offset;
 
 815                 String lineContents = document.get(firstChar, length);
 
 817                 String prefix = lineContents.trim();
 
 818                 if (!prefix.startsWith("*") || prefix.startsWith("*/")) //$NON-NLS-1$ //$NON-NLS-2$
 
 821                 lineContents = lineContents.substring(1).trim().toLowerCase();
 
 823                 // preserve empty lines
 
 824                 if (lineContents.length() == 0)
 
 828                 if (lineContents.startsWith("@")) //$NON-NLS-1$
 
 831                 // preserve HTML tags which are not inline
 
 832                 if (lineContents.startsWith("<") && !isInlineTag(lineContents)) //$NON-NLS-1$
 
 838         protected void jdocHandleBackspaceDelete(IDocument document,
 
 841                 if (!getPreferenceStore().getBoolean(
 
 842                                 PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
 
 846                         String text = document.get(c.offset, c.length);
 
 847                         int line = document.getLineOfOffset(c.offset);
 
 848                         int lineOffset = document.getLineOffset(line);
 
 850                         // erase line delimiter
 
 851                         String lineDelimiter = document.getLineDelimiter(line);
 
 852                         if (lineDelimiter != null && lineDelimiter.equals(text)) {
 
 854                                 String prefix = jdocExtractLinePrefix(document, line + 1);
 
 856                                 // strip prefix if any
 
 857                                 if (prefix.length() > 0) {
 
 858                                         int length = document.getLineDelimiter(line).length()
 
 860                                         document.replace(c.offset, length, null);
 
 867                                 // backspace: beginning of a javadoc line
 
 868                         } else if (document.getChar(c.offset - 1) == '*'
 
 869                                         && jdocExtractLinePrefix(document, line).length() - 1 >= c.offset
 
 872                                 lineDelimiter = document.getLineDelimiter(line - 1);
 
 873                                 String prefix = jdocExtractLinePrefix(document, line);
 
 874                                 int length = (lineDelimiter != null ? lineDelimiter.length()
 
 877                                 document.replace(c.offset - length + 1, length, null);
 
 880                                 c.offset -= length - 1;
 
 885                                 document.replace(c.offset, c.length, null);
 
 890                 } catch (BadLocationException e) {
 
 895                         int line = document.getLineOfOffset(c.offset);
 
 896                         int lineOffset = document.getLineOffset(line);
 
 897                         String prefix = jdocExtractLinePrefix(document, line);
 
 898                         boolean always = c.offset > lineOffset
 
 899                                         && c.offset <= lineOffset + prefix.length();
 
 900                         int[] caretOffset = { c.offset };
 
 901                         jdocWrapParagraphFromLine(document, document
 
 902                                         .getLineOfOffset(c.offset), caretOffset, always);
 
 903                         c.offset = caretOffset[0];
 
 905                 } catch (BadLocationException e) {
 
 911          * Returns the compilation unit of the CompilationUnitEditor invoking the
 
 912          * AutoIndentStrategy, might return <code>null</code> on error.
 
 914         private static ICompilationUnit getCompilationUnit() {
 
 916                 IWorkbenchWindow window = PlatformUI.getWorkbench()
 
 917                                 .getActiveWorkbenchWindow();
 
 921                 IWorkbenchPage page = window.getActivePage();
 
 925                 IEditorPart editor = page.getActiveEditor();
 
 929                 IWorkingCopyManager manager = WebUI.getDefault()
 
 930                                 .getWorkingCopyManager();
 
 931                 ICompilationUnit unit = manager.getWorkingCopy(editor.getEditorInput());