Added auto indent strategy for phpdocs and comments
authorjsurfer <jsurfer>
Fri, 8 Oct 2004 18:49:26 +0000 (18:49 +0000)
committerjsurfer <jsurfer>
Fri, 8 Oct 2004 18:49:26 +0000 (18:49 +0000)
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/PHPSourceViewerConfiguration.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java

index 2dfafd5..020ffd2 100644 (file)
@@ -460,9 +460,9 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     //        .add(new OverlayPreferenceStore.OverlayKey(
     //            OverlayPreferenceStore.BOOLEAN,
     //            PreferenceConstants.EDITOR_CLOSE_BRACES));
-    //    overlayKeys.add(new OverlayPreferenceStore.OverlayKey(
-    //        OverlayPreferenceStore.BOOLEAN,
-    //        PreferenceConstants.EDITOR_CLOSE_JAVADOCS));
+        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(
+            OverlayPreferenceStore.BOOLEAN,
+            PreferenceConstants.EDITOR_CLOSE_JAVADOCS));
     overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_WRAP_WORDS));
     overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_WRAP_STRINGS_DQ));
     overlayKeys
@@ -1108,11 +1108,11 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     //    //$NON-NLS-1$
     //    addCheckBox(group, label, PreferenceConstants.EDITOR_CLOSE_BRACES, 1);
 
-    //    label = PreferencesMessages
-    //        .getString("JavaEditorPreferencePage.closeJavaDocs");
-    //    //$NON-NLS-1$
-    //    button = addCheckBox(group, label,
-    //        PreferenceConstants.EDITOR_CLOSE_JAVADOCS, 1);
+        label = PreferencesMessages
+            .getString("JavaEditorPreferencePage.closeJavaDocs");
+        //$NON-NLS-1$
+        button = addCheckBox(group, label,
+            PreferenceConstants.EDITOR_CLOSE_JAVADOCS, 1);
     //
     //    label = PreferencesMessages
     //        .getString("JavaEditorPreferencePage.addJavaDocTags");
@@ -1445,9 +1445,9 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     fBackgroundDefaultRadioButton.setSelection(default_);
     fBackgroundCustomRadioButton.setSelection(!default_);
     fBackgroundColorButton.setEnabled(!default_);
-    //    boolean closeJavaDocs = fOverlayStore
-    //        .getBoolean(PreferenceConstants.EDITOR_CLOSE_JAVADOCS);
-    //    fAddJavaDocTagsButton.setEnabled(closeJavaDocs);
+        boolean closeJavaDocs = fOverlayStore
+            .getBoolean(PreferenceConstants.EDITOR_CLOSE_JAVADOCS);
+//        fAddJavaDocTagsButton.setEnabled(closeJavaDocs);
     fEscapeStringsButtonDQ.setEnabled(fOverlayStore.getBoolean(PreferenceConstants.EDITOR_WRAP_STRINGS_DQ));
     fEscapeStringsButtonSQ.setEnabled(fOverlayStore.getBoolean(PreferenceConstants.EDITOR_WRAP_STRINGS_SQ));
     //         boolean fillMethodArguments=
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java
new file mode 100644 (file)
index 0000000..40f04d2
--- /dev/null
@@ -0,0 +1,838 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package net.sourceforge.phpdt.internal.ui.text.phpdoc;
+
+import java.text.BreakIterator;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IMethod;
+import net.sourceforge.phpdt.core.ISourceRange;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+import net.sourceforge.phpdt.ui.CodeGeneration;
+import net.sourceforge.phpdt.ui.IWorkingCopyManager;
+import net.sourceforge.phpdt.ui.PreferenceConstants;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DefaultAutoIndentStrategy;
+import org.eclipse.jface.text.DocumentCommand;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.ITextEditorExtension3;
+
+
+/**
+ * Auto indent strategy for java doc comments
+ */
+public class JavaDocAutoIndentStrategy extends DefaultAutoIndentStrategy {
+
+       private String fPartitioning;
+
+       /**
+        * Creates a new Javadoc auto indent strategy for the given document partitioning.
+        * 
+        * @param partitioning the document partitioning
+        */
+       public JavaDocAutoIndentStrategy(String partitioning) {
+               fPartitioning= partitioning;
+       }
+       
+       private static String getLineDelimiter(IDocument document) {
+               try {
+                       if (document.getNumberOfLines() > 1)
+                               return document.getLineDelimiter(0);
+               } catch (BadLocationException e) {
+                 PHPeclipsePlugin.log(e);
+               }       
+
+               return System.getProperty("line.separator"); //$NON-NLS-1$
+       }
+
+       /**
+        * Copies the indentation of the previous line and add a star.
+        * If the javadoc just started on this line add standard method tags
+        * and close the javadoc.
+        *
+        * @param d the document to work on
+        * @param c the command to deal with
+        */
+       private void jdocIndentAfterNewLine(IDocument d, DocumentCommand c) {
+               
+               if (c.offset == -1 || d.getLength() == 0)
+                       return;
+                       
+               try {
+                       // find start of line
+                       int p= (c.offset == d.getLength() ? c.offset  - 1 : c.offset);
+                       IRegion info= d.getLineInformationOfOffset(p);
+                       int start= info.getOffset();
+                       
+                       // find white spaces
+                       int end= findEndOfWhiteSpace(d, start, c.offset);
+                       
+                       StringBuffer buf= new StringBuffer(c.text);
+                       if (end >= start) {     // 1GEYL1R: ITPJUI:ALL - java doc edit smartness not work for class comments
+                               // append to input
+                               String indentation= jdocExtractLinePrefix(d, d.getLineOfOffset(c.offset));
+                               buf.append(indentation);
+                               if (end < c.offset) {
+                                       if (d.getChar(end) == '/') {
+                                               // javadoc started on this line
+                                               buf.append(" * "); //$NON-NLS-1$
+
+                                               if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CLOSE_JAVADOCS) && isNewComment(d, c.offset, fPartitioning)) {
+                                                       String lineDelimiter= getLineDelimiter(d);
+                                                       
+                                                       String endTag= lineDelimiter + indentation + " */"; //$NON-NLS-1$
+                                                       d.replace(c.offset, 0, endTag); //$NON-NLS-1$
+                                                       // evaluate method signature
+                                                       ICompilationUnit unit= getCompilationUnit();
+
+//                                                     if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS) &&
+//                                                             unit != null)
+//                                                     {
+//                                                             try {
+//                                                                     JavaModelUtil.reconcile(unit);
+//                                                                     String string= createJavaDocTags(d, c, indentation, lineDelimiter, unit);
+//                                                                     if (string != null) {
+//                                                                             d.replace(c.offset, 0, string);
+//                                                                     }
+//                                                             } catch (CoreException e) {
+//                                                                     // ignore
+//                                                             }
+//                                                     }
+                                               }                                               
+
+                                       }
+                               }                       
+                       }
+                       
+                       c.text= buf.toString();
+                       
+               } catch (BadLocationException excp) {
+                       // stop work
+               }
+       }
+
+       private String createJavaDocTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, ICompilationUnit unit)
+               throws CoreException, BadLocationException
+       {
+               IJavaElement element= unit.getElementAt(command.offset);
+               if (element == null)
+                       return null;
+
+               switch (element.getElementType()) {
+               case IJavaElement.TYPE:
+                       return createTypeTags(document, command, indentation, lineDelimiter, (IType) element);  
+
+               case IJavaElement.METHOD:
+                       return createMethodTags(document, command, indentation, lineDelimiter, (IMethod) element);
+
+               default:
+                       return null;
+               }               
+       }
+       
+       /*
+        * Removes start and end of a comment and corrects indentation and line delimiters.
+        */
+       private String prepareTemplateComment(String comment, String indentation, String lineDelimiter) {
+               //      trim comment start and end if any
+               if (comment.endsWith("*/")) //$NON-NLS-1$
+                       comment= comment.substring(0, comment.length() - 2);
+               comment= comment.trim();
+               if (comment.startsWith("/*")) { //$NON-NLS-1$
+                       if (comment.length() > 2 && comment.charAt(2) == '*') {
+                               comment= comment.substring(3); // remove '/**'
+                       } else {
+                               comment= comment.substring(2); // remove '/*'
+                       }
+               }
+//             return Strings.changeIndent(comment, 0, CodeFormatterUtil.getTabWidth(), indentation, lineDelimiter);
+               return Strings.changeIndent(comment, 0, getTabWidth(), indentation, lineDelimiter);
+       }
+       
+       public static int getTabWidth() {
+               Preferences preferences= PHPeclipsePlugin.getDefault().getPluginPreferences();
+               return preferences.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
+       }
+       
+       private String createTypeTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IType type)
+               throws CoreException
+       {
+               String comment= CodeGeneration.getTypeComment(type.getCompilationUnit(), type.getTypeQualifiedName('.'), lineDelimiter);
+               if (comment != null) {
+                       return prepareTemplateComment(comment.trim(), indentation, lineDelimiter);
+               }
+               return null;
+       }
+       
+       private String createMethodTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IMethod method)
+               throws CoreException, BadLocationException
+       {
+               IRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset, false);
+               ISourceRange sourceRange= method.getSourceRange();
+               if (sourceRange == null || sourceRange.getOffset() != partition.getOffset())
+                       return null;
+                       
+//             IMethod inheritedMethod= getInheritedMethod(method);
+//             String comment= CodeGeneration.getMethodComment(method, inheritedMethod, lineDelimiter);
+//             if (comment != null) {
+//                     comment= comment.trim();
+//                     boolean javadocComment= comment.startsWith("/**"); //$NON-NLS-1$
+//                     boolean isJavaDoc= partition.getLength() >= 3 && document.get(partition.getOffset(), 3).equals("/**"); //$NON-NLS-1$
+//                     if (javadocComment == isJavaDoc) {
+//                             return prepareTemplateComment(comment, indentation, lineDelimiter);
+//                     }
+//             }
+               return null;
+       }
+
+       /**
+        * Returns the method inherited from, <code>null</code> if method is newly defined.
+        */
+//     private static IMethod getInheritedMethod(IMethod method) throws JavaModelException {
+//             IType declaringType= method.getDeclaringType();
+//             ITypeHierarchy typeHierarchy= SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
+//             return JavaModelUtil.findMethodDeclarationInHierarchy(typeHierarchy, declaringType,
+//                     method.getElementName(), method.getParameterTypes(), method.isConstructor());
+//     }
+       
+       protected void jdocIndentForCommentEnd(IDocument d, DocumentCommand c) {
+               if (c.offset < 2 || d.getLength() == 0) {
+                       return;
+               }
+               try {
+                       if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
+                               // modify document command
+                               c.length++;
+                               c.offset--;
+                       }                                       
+               } catch (BadLocationException excp) {
+                       // stop work
+               }
+       }
+
+       /**
+        * Guesses if the command operates within a newly created javadoc comment or not.
+        * If in doubt, it will assume that the javadoc is new.
+        */
+       private static boolean isNewComment(IDocument document, int commandOffset, String partitioning) {
+               
+               try {
+                       int lineIndex= document.getLineOfOffset(commandOffset) + 1;
+                       if (lineIndex >= document.getNumberOfLines())
+                               return true;
+                       
+                       IRegion line= document.getLineInformation(lineIndex);
+                       ITypedRegion partition= TextUtilities.getPartition(document, partitioning, commandOffset, false);
+                       int partitionEnd= partition.getOffset() + partition.getLength();
+                       if (line.getOffset() >= partitionEnd)
+                               return false;
+                       
+                       if (document.getLength() == partitionEnd)
+                               return true; // partition goes to end of document - probably a new comment
+                       
+                       String comment= document.get(partition.getOffset(), partition.getLength());
+                       if (comment.indexOf("/*", 2) != -1) //$NON-NLS-1$
+                               return true; // enclosed another comment -> probably a new comment
+                       
+                       return false;
+                       
+               } catch (BadLocationException e) {
+                       return false;
+               }                       
+       }
+       
+       private boolean isSmartMode() {
+               IWorkbenchPage page= PHPeclipsePlugin.getActivePage();
+               if (page != null)  {
+                       IEditorPart part= page.getActiveEditor(); 
+                       if (part instanceof ITextEditorExtension3) {
+                               ITextEditorExtension3 extension= (ITextEditorExtension3) part;
+                               return extension.getInsertMode() == ITextEditorExtension3.SMART_INSERT;
+                       }
+               }
+               return false;
+       }
+
+       /*
+        * @see IAutoIndentStrategy#customizeDocumentCommand
+        */
+       public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
+               
+               if (!isSmartMode())
+                       return;
+
+               try {
+                       
+                       if (command.text != null && command.length == 0) {
+                               String[] lineDelimiters= document.getLegalLineDelimiters();
+                               int index= TextUtilities.endsWith(lineDelimiters, command.text);
+                               if (index > -1) {
+                                       // ends with line delimiter
+                                       if (lineDelimiters[index].equals(command.text))
+                                               // just the line delimiter
+                                               jdocIndentAfterNewLine(document, command);
+                                       return;
+                               }
+                       }
+                       
+                       if (command.text != null && command.text.equals("/")) { //$NON-NLS-1$
+                               jdocIndentForCommentEnd(document, command);
+                               return;
+                       }
+
+                       ITypedRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset, true);
+                       int partitionStart= partition.getOffset();
+                       int partitionEnd= partition.getLength() + partitionStart;                       
+                       
+                       String text= command.text;
+                       int offset= command.offset;
+                       int length= command.length;
+
+                       // partition change
+                       final int PREFIX_LENGTH= "/*".length(); //$NON-NLS-1$
+                       final int POSTFIX_LENGTH= "*/".length(); //$NON-NLS-1$
+                       if ((offset < partitionStart + PREFIX_LENGTH || offset + length > partitionEnd - POSTFIX_LENGTH) ||
+                               text != null && text.length() >= 2 && ((text.indexOf("*/") != -1) || (document.getChar(offset) == '*' && text.startsWith("/")))) //$NON-NLS-1$ //$NON-NLS-2$
+                               return;                 
+
+                       if (command.text == null || command.text.length() == 0)
+                               jdocHandleBackspaceDelete(document, command);
+               
+                       else if (command.text != null && command.length == 0 && command.text.length() > 0)
+                               jdocWrapParagraphOnInsert(document, command);
+
+               } catch (BadLocationException e) {
+                 PHPeclipsePlugin.log(e);
+               }
+       }
+
+       private void flushCommand(IDocument document, DocumentCommand command) throws BadLocationException {
+
+               if (!command.doit)
+                       return;
+               
+               document.replace(command.offset, command.length, command.text);
+
+               command.doit= false;
+               if (command.text != null)
+                       command.offset += command.text.length();
+               command.length= 0;
+               command.text= null;                     
+       }
+
+       protected void jdocWrapParagraphOnInsert(IDocument document, DocumentCommand command) throws BadLocationException {
+
+//             Assert.isTrue(command.length == 0);
+//             Assert.isTrue(command.text != null && command.text.length() == 1);
+               
+               if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
+                       return;
+
+               int line= document.getLineOfOffset(command.offset);
+               IRegion region= document.getLineInformation(line);
+               int lineOffset= region.getOffset();
+               int lineLength= region.getLength();
+
+               String lineContents= document.get(lineOffset, lineLength);                                              
+               StringBuffer buffer= new StringBuffer(lineContents);
+               int start= command.offset - lineOffset;
+               int end= command.length + start; 
+               buffer.replace(start, end, command.text);
+               
+               // handle whitespace            
+               if (command.text != null && command.text.length() != 0 && command.text.trim().length() == 0) {
+
+                       String endOfLine= document.get(command.offset, lineOffset + lineLength - command.offset);
+
+                       // end of line
+                       if (endOfLine.length() == 0) {
+                               // move caret to next line
+                               flushCommand(document, command);
+
+                               if (isLineTooShort(document, line)) { 
+                                       int[] caretOffset= {command.offset};
+                                       jdocWrapParagraphFromLine(document, line, caretOffset, false);
+                                       command.offset= caretOffset[0];
+                                       return;
+                               }
+
+                               // move caret to next line if possible
+                               if (line < document.getNumberOfLines() - 1 && isJavaDocLine(document, line + 1)) {
+                                       String lineDelimiter= document.getLineDelimiter(line);
+                                       String nextLinePrefix= jdocExtractLinePrefix(document, line + 1);
+                                       command.offset += lineDelimiter.length() + nextLinePrefix.length();
+                               } 
+                               return;
+
+                       // inside whitespace at end of line
+                       } else if (endOfLine.trim().length() == 0) {
+                               // simply insert space
+                               return; 
+                       }
+               }
+
+               // change in prefix region
+               String prefix= jdocExtractLinePrefix(document, line);
+               boolean wrapAlways=     command.offset >= lineOffset && command.offset <= lineOffset + prefix.length();
+
+               // must insert the text now because it may include whitepace
+               flushCommand(document, command);                
+
+               if (wrapAlways || calculateDisplayedWidth(buffer.toString()) > getMargin() || isLineTooShort(document, line)) {
+                       int[] caretOffset= {command.offset};                                                            
+                       jdocWrapParagraphFromLine(document, line, caretOffset, wrapAlways);
+
+                       if (!wrapAlways)        
+                               command.offset= caretOffset[0];
+               }
+       }
+
+       /**
+        * Method jdocWrapParagraphFromLine.
+        * 
+        * @param document
+        * @param line
+        * @param always
+        */
+       private void jdocWrapParagraphFromLine(IDocument document, int line, int[] caretOffset, boolean always) throws BadLocationException {
+
+               String indent= jdocExtractLinePrefix(document, line);
+               if (!always) {
+                       if (!indent.trim().startsWith("*")) //$NON-NLS-1$
+                               return;
+
+                       if (indent.trim().startsWith("*/")) //$NON-NLS-1$
+                               return;
+
+                       if (!isLineTooLong(document, line) && !isLineTooShort(document, line))
+                               return;
+               }
+               
+               boolean caretRelativeToParagraphOffset= false;
+               int caret= caretOffset[0];
+
+               int caretLine= document.getLineOfOffset(caret);
+               int lineOffset= document.getLineOffset(line);
+               int paragraphOffset= lineOffset + indent.length();
+               if (paragraphOffset < caret) {
+                       caret -= paragraphOffset;
+                       caretRelativeToParagraphOffset= true;
+               } else {
+                       caret -= lineOffset;
+               }
+
+               StringBuffer buffer= new StringBuffer();
+               int currentLine= line;
+               while (line == currentLine || isJavaDocLine(document, currentLine)) {
+                       
+                       if (buffer.length() != 0 && !Character.isWhitespace(buffer.charAt(buffer.length() - 1))) {
+                               buffer.append(' ');
+                               if (currentLine <= caretLine) {
+                                       // in this case caretRelativeToParagraphOffset is always true
+                                       ++caret;
+                               }
+                       }
+
+                       String string= getLineContents(document, currentLine);                  
+                       buffer.append(string);
+                       currentLine++;
+               }
+               String paragraph= buffer.toString();
+               
+               if (paragraph.trim().length() == 0)
+                       return;
+
+               caretOffset[0]= caretRelativeToParagraphOffset ? caret : 0;
+               String delimiter= document.getLineDelimiter(0);
+               String wrapped= formatParagraph(paragraph, caretOffset, indent, delimiter, getMargin());
+
+               int beginning= document.getLineOffset(line);
+               int end= document.getLineOffset(currentLine);
+               document.replace(beginning, end - beginning, wrapped.toString());
+
+               caretOffset[0]= caretRelativeToParagraphOffset ? caretOffset[0] + beginning : caret + beginning;
+       }
+       
+       /**
+        * Line break iterator to handle whitespaces as first class citizens. 
+        */
+       private static class LineBreakIterator {
+               
+               private final String fString;
+               private final BreakIterator fIterator= BreakIterator.getLineInstance();
+                               
+               private int fStart;
+               private int fEnd;
+               private int fBufferedEnd;
+               
+               public LineBreakIterator(String string) {
+                       fString= string;
+                       fIterator.setText(string);
+               }
+               
+               public int first() {
+                       fBufferedEnd= -1;
+                       fStart= fIterator.first();
+                       return fStart;  
+               }
+               
+               public int next() {
+                       
+                       if (fBufferedEnd != -1) {
+                               fStart= fEnd;
+                               fEnd= fBufferedEnd;
+                               fBufferedEnd= -1;
+                               return fEnd;
+                       }
+
+                       fStart= fEnd;
+                       fEnd= fIterator.next();
+
+                       if (fEnd == BreakIterator.DONE)
+                               return fEnd;
+
+                       final String string= fString.substring(fStart, fEnd);
+
+                       // whitespace
+                       if (string.trim().length() == 0)
+                               return fEnd;
+
+                       final String word= string.trim();
+                       if (word.length() == string.length())
+                               return fEnd;
+                       
+                       // suspected whitespace
+                       fBufferedEnd= fEnd;
+                       return fStart + word.length();
+               }       
+       }
+       
+       /**
+        * Formats a paragraph, using break iterator.  
+        * 
+        * @param offset an offset within the paragraph, which will be updated with respect to formatting.
+        */
+       private static String formatParagraph(String paragraph, int[] offset, String prefix, String lineDelimiter, int margin) {
+
+               LineBreakIterator iterator= new LineBreakIterator(paragraph);
+
+               StringBuffer paragraphBuffer= new StringBuffer();
+               StringBuffer lineBuffer= new StringBuffer();
+               StringBuffer whiteSpaceBuffer= new StringBuffer();
+               
+               int index= offset[0];
+               int indexBuffer= -1;
+
+         // line delimiter could be null
+        if (lineDelimiter == null)
+            lineDelimiter= ""; //$NON-NLS-1$
+
+               for (int start= iterator.first(), end= iterator.next(); end != BreakIterator.DONE; start= end, end= iterator.next()) {
+
+                       String word= paragraph.substring(start, end);
+
+                       // word is whitespace
+                       if (word.trim().length() == 0) {
+                               whiteSpaceBuffer.append(word);
+
+                       // first word of line is always appended                        
+                       } else if (lineBuffer.length() == 0) {
+                               lineBuffer.append(prefix);
+                               lineBuffer.append(whiteSpaceBuffer.toString());
+                               lineBuffer.append(word);
+
+                       } else {
+                               String line= lineBuffer.toString() + whiteSpaceBuffer.toString()  + word.toString();
+                               
+                               // margin exceeded 
+                               if (calculateDisplayedWidth(line) > margin) {
+                                       // flush line buffer and wrap paragraph
+                                       paragraphBuffer.append(lineBuffer.toString());
+                                       paragraphBuffer.append(lineDelimiter);
+                                       lineBuffer.setLength(0);
+                                       lineBuffer.append(prefix);
+                                       lineBuffer.append(word);
+
+                                       // flush index buffer
+                                       if (indexBuffer != -1) {
+                                               offset[0]= indexBuffer;
+                                               // correct for caret in whitespace at the end of line
+                                               if (whiteSpaceBuffer.length() != 0 && index < start && index >= start - whiteSpaceBuffer.length())
+                                                       offset[0] -= (index - (start - whiteSpaceBuffer.length()));
+                                               indexBuffer= -1;
+                                       }
+
+                                       whiteSpaceBuffer.setLength(0);
+
+                               // margin not exceeded
+                               } else {
+                                       lineBuffer.append(whiteSpaceBuffer.toString());
+                                       lineBuffer.append(word);
+                                       whiteSpaceBuffer.setLength(0);
+                               }
+                       }
+
+                       if (index >= start && index < end) {
+                               indexBuffer= paragraphBuffer.length() + lineBuffer.length() + (index - start);
+                               if (word.trim().length() != 0)
+                                       indexBuffer -= word.length();
+                       }
+               }
+
+               // flush line buffer            
+               paragraphBuffer.append(lineBuffer.toString());
+               paragraphBuffer.append(lineDelimiter);
+
+               // flush index buffer
+               if (indexBuffer != -1)  
+                       offset[0]= indexBuffer;
+
+               // last position is not returned by break iterator
+               else if (offset[0] == paragraph.length())
+                       offset[0]= paragraphBuffer.length() - lineDelimiter.length();
+                       
+               return paragraphBuffer.toString();
+       }
+
+       private static IPreferenceStore getPreferenceStore() {
+               return PHPeclipsePlugin.getDefault().getPreferenceStore();              
+       }
+
+       /**
+        * Returns the displayed width of a string, taking in account the displayed tab width.
+        * The result can be compared against the print margin.
+        */
+       private static int calculateDisplayedWidth(String string) {
+
+               int tabWidth= getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); 
+               if (tabWidth<=0) {
+                 tabWidth = 2;
+               }
+               int column= 0;
+               for (int i= 0; i < string.length(); i++)
+                       if ('\t' == string.charAt(i))
+                               column += tabWidth - (column % tabWidth);
+                       else
+                               column++;
+                               
+               return column;
+       }
+
+       private String jdocExtractLinePrefix(IDocument d, int line) throws BadLocationException {
+
+               IRegion region= d.getLineInformation(line);
+               int lineOffset= region.getOffset();
+               int index= findEndOfWhiteSpace(d, lineOffset, lineOffset + d.getLineLength(line));
+               if (d.getChar(index) == '*') {
+                       index++;
+                       if (index != lineOffset + region.getLength() &&d.getChar(index) == ' ')
+                               index++;
+               }
+               return d.get(lineOffset, index - lineOffset);
+       }
+
+       private String getLineContents(IDocument d, int line) throws BadLocationException {
+               int offset = d.getLineOffset(line);
+               int length = d.getLineLength(line);
+        String lineDelimiter= d.getLineDelimiter(line);
+        if (lineDelimiter != null)
+            length= length - lineDelimiter.length();
+               String lineContents = d.get(offset, length);
+               int trim = jdocExtractLinePrefix(d, line).length();
+               return lineContents.substring(trim);
+       }
+       
+       private static String getLine(IDocument document, int line) throws BadLocationException {
+               IRegion region= document.getLineInformation(line);              
+               return document.get(region.getOffset(), region.getLength());            
+       }
+
+       /**
+        * Returns <code>true</code> if the javadoc line is too short, <code>false</code> otherwise.
+        */
+       private boolean isLineTooShort(IDocument document, int line) throws BadLocationException {
+
+               if (!isJavaDocLine(document, line + 1))
+                       return false;
+
+               String nextLine= getLineContents(document, line + 1);
+               if (nextLine.trim().length() == 0)
+                       return false;
+
+               return true;
+       }
+
+       /**
+        * Returns <code>true</code> if the line is too long, <code>false</code> otherwise.
+        */
+       private boolean isLineTooLong(IDocument document, int line) throws BadLocationException {
+               String lineContents= getLine(document, line);
+               return calculateDisplayedWidth(lineContents) > getMargin();
+       }
+
+       private static int getMargin() {
+               return getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN);
+       }
+
+       private static final String[] fgInlineTags= {
+               "<b>", "<i>", "<em>", "<strong>", "<code>"  //$NON-NLS-1$  //$NON-NLS-2$  //$NON-NLS-3$  //$NON-NLS-4$ //$NON-NLS-5$
+       };
+       
+       private boolean isInlineTag(String string) {
+               for (int i= 0; i < fgInlineTags.length; i++)
+                       if (string.startsWith(fgInlineTags[i]))
+                               return true;    
+               return false;
+       }
+       
+       /**
+        * returns true if the specified line is part of a paragraph and should be merged with
+        * the previous line.
+        */
+       private boolean isJavaDocLine(IDocument document, int line) throws BadLocationException {
+
+               if (document.getNumberOfLines() < line)
+                       return false;
+
+               int offset= document.getLineOffset(line);
+               int length= document.getLineLength(line);
+               int firstChar= findEndOfWhiteSpace(document, offset, offset + length);
+               length -= firstChar - offset;
+               String lineContents= document.get(firstChar, length);
+
+               String prefix= lineContents.trim();             
+               if (!prefix.startsWith("*") || prefix.startsWith("*/")) //$NON-NLS-1$ //$NON-NLS-2$
+                       return false;
+                       
+               lineContents= lineContents.substring(1).trim().toLowerCase();
+
+               // preserve empty lines
+               if (lineContents.length() == 0)
+                       return false;
+
+               // preserve @TAGS
+               if (lineContents.startsWith("@")) //$NON-NLS-1$
+                       return false;
+
+               // preserve HTML tags which are not inline
+               if (lineContents.startsWith("<") && !isInlineTag(lineContents)) //$NON-NLS-1$
+                       return false;
+
+               return true;
+       }
+
+       protected void jdocHandleBackspaceDelete(IDocument document, DocumentCommand c) {
+               
+               if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
+                       return;
+                       
+               try {
+                       String text= document.get(c.offset, c.length);
+                       int line= document.getLineOfOffset(c.offset);
+                       int lineOffset= document.getLineOffset(line);
+
+                       // erase line delimiter
+                       String lineDelimiter= document.getLineDelimiter(line);
+                       if (lineDelimiter != null && lineDelimiter.equals(text)) {
+                               
+                               String prefix= jdocExtractLinePrefix(document, line + 1);
+
+                               // strip prefix if any
+                               if (prefix.length() > 0) {
+                                       int length= document.getLineDelimiter(line).length() + prefix.length();
+                                       document.replace(c.offset, length, null);
+
+                                       c.doit= false;
+                                       c.length= 0;
+                                       return;
+                               }
+
+                       // backspace: beginning of a javadoc line
+                       } else if (document.getChar(c.offset - 1) == '*' && jdocExtractLinePrefix(document, line).length() - 1 >= c.offset - lineOffset) {
+
+                               lineDelimiter= document.getLineDelimiter(line - 1);
+                               String prefix= jdocExtractLinePrefix(document, line);
+                               int length= (lineDelimiter != null ? lineDelimiter.length() : 0) + prefix.length();
+                               document.replace(c.offset - length + 1, length, null);
+
+                               c.doit= false;
+                               c.offset -= length - 1;
+                               c.length= 0;
+                               return;
+
+                       } else {
+                               document.replace(c.offset, c.length, null);
+                               c.doit= false;
+                               c.length= 0;
+                       }
+
+               } catch (BadLocationException e) {
+                 PHPeclipsePlugin.log(e);
+               }
+                               
+               try {
+                       int line= document.getLineOfOffset(c.offset);
+                       int lineOffset= document.getLineOffset(line);
+                       String prefix= jdocExtractLinePrefix(document, line);
+                       boolean always= c.offset > lineOffset && c.offset <= lineOffset + prefix.length();
+                       int[] caretOffset= {c.offset};
+                       jdocWrapParagraphFromLine(document, document.getLineOfOffset(c.offset), caretOffset, always);
+                       c.offset= caretOffset[0];
+
+               } catch (BadLocationException e) {
+                 PHPeclipsePlugin.log(e);
+               }
+       }
+
+       /**
+        * Returns the compilation unit of the CompilationUnitEditor invoking the AutoIndentStrategy,
+        * might return <code>null</code> on error.
+        */
+       private static ICompilationUnit getCompilationUnit() {
+
+               IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+               if (window == null)
+                       return null;
+                       
+               IWorkbenchPage page= window.getActivePage();
+               if (page == null)       
+                       return null;
+
+               IEditorPart editor= page.getActiveEditor();
+               if (editor == null)
+                       return null;
+
+               IWorkingCopyManager manager= PHPeclipsePlugin.getDefault().getWorkingCopyManager();
+               ICompilationUnit unit= manager.getWorkingCopy(editor.getEditorInput());
+               if (unit == null)
+                       return null;
+
+               return unit;
+       }
+                       
+}
index 95b7d94..98dccbb 100644 (file)
@@ -23,6 +23,7 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
 import org.eclipse.ui.texteditor.AbstractTextEditor;
 
 //
@@ -513,7 +514,7 @@ public class PreferenceConstants {
    * Value is of type <code>Int</code>: positive int value specifying the number of spaces per tab.
    * </p>
    */
-  public final static String EDITOR_TAB_WIDTH = "net.sourceforge.phpdt.ui.editor.tab.width"; //$NON-NLS-1$
+  public final static String EDITOR_TAB_WIDTH = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH; //"net.sourceforge.phpdt.ui.editor.tab.width"; //$NON-NLS-1$
 
   /**
    * A named preference that controls whether the outline view selection should stay in sync with with the element at the current
index d1e9583..d5e5073 100644 (file)
@@ -31,6 +31,7 @@ import net.sourceforge.phpdt.internal.ui.text.java.JavaStringAutoIndentStrategyS
 import net.sourceforge.phpdt.internal.ui.text.java.hover.JavaEditorTextHoverDescriptor;
 import net.sourceforge.phpdt.internal.ui.text.java.hover.JavaEditorTextHoverProxy;
 import net.sourceforge.phpdt.internal.ui.text.java.hover.JavaInformationProvider;
+import net.sourceforge.phpdt.internal.ui.text.phpdoc.JavaDocAutoIndentStrategy;
 import net.sourceforge.phpdt.internal.ui.text.phpdoc.PHPDocCodeScanner;
 import net.sourceforge.phpdt.internal.ui.text.phpdoc.PHPDocCompletionProcessor;
 import net.sourceforge.phpdt.ui.PreferenceConstants;
@@ -220,41 +221,42 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
     fPreferenceStore = preferenceStore;
     fTextEditor = editor;
     fDocumentPartitioning = partitioning;
-//    fJavaTextTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
+    //    fJavaTextTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
     fXMLTextTools = XMLPlugin.getDefault().getXMLTextTools();
     xmlConfiguration = new XMLConfiguration(fXMLTextTools);
-    fColorManager= colorManager;
-       fPreferenceStore= preferenceStore;
-       fTextEditor= editor;
-       fDocumentPartitioning= partitioning;
-       
+    fColorManager = colorManager;
+    fPreferenceStore = preferenceStore;
+    fTextEditor = editor;
+    fDocumentPartitioning = partitioning;
+
     initializeScanners();
   }
 
   /**
-        * Creates a new Java source viewer configuration for viewers in the given editor 
-        * using the given Java tools.
-        *
-        * @param tools the Java text tools to be used
-        * @param editor the editor in which the configured viewer(s) will reside
-        * @see JavaTextTools
-        * @deprecated As of 3.0, replaced by {@link JavaSourceViewerConfiguration#JavaSourceViewerConfiguration(IColorManager, IPreferenceStore, ITextEditor, String)}
-        */
-//  public PHPSourceViewerConfiguration(JavaTextTools tools, PHPEditor editor, String partitioning) {
-//    fJavaTextTools = tools;
-//    fColorManager = tools.getColorManager();
-//    fPreferenceStore = createPreferenceStore();
-//    fDocumentPartitioning = partitioning;
-//    fCodeScanner = (AbstractJavaScanner) fJavaTextTools.getCodeScanner();
-//    fMultilineCommentScanner = (AbstractJavaScanner) fJavaTextTools.getMultilineCommentScanner();
-//    fSinglelineCommentScanner = (AbstractJavaScanner) fJavaTextTools.getSinglelineCommentScanner();
-//    fStringScanner = (AbstractJavaScanner) fJavaTextTools.getStringScanner();
-//    fJavaDocScanner = (AbstractJavaScanner) fJavaTextTools.getJavaDocScanner();
-//    fTextEditor = editor;
-//    fXMLTextTools = XMLPlugin.getDefault().getXMLTextTools();
-//    xmlConfiguration = new XMLConfiguration(fXMLTextTools);
-//  }
-
+   * Creates a new Java source viewer configuration for viewers in the given editor using the given Java tools.
+   * 
+   * @param tools
+   *          the Java text tools to be used
+   * @param editor
+   *          the editor in which the configured viewer(s) will reside
+   * @see JavaTextTools
+   * @deprecated As of 3.0, replaced by
+   *             {@link JavaSourceViewerConfiguration#JavaSourceViewerConfiguration(IColorManager, IPreferenceStore, ITextEditor, String)}
+   */
+  //  public PHPSourceViewerConfiguration(JavaTextTools tools, PHPEditor editor, String partitioning) {
+  //    fJavaTextTools = tools;
+  //    fColorManager = tools.getColorManager();
+  //    fPreferenceStore = createPreferenceStore();
+  //    fDocumentPartitioning = partitioning;
+  //    fCodeScanner = (AbstractJavaScanner) fJavaTextTools.getCodeScanner();
+  //    fMultilineCommentScanner = (AbstractJavaScanner) fJavaTextTools.getMultilineCommentScanner();
+  //    fSinglelineCommentScanner = (AbstractJavaScanner) fJavaTextTools.getSinglelineCommentScanner();
+  //    fStringScanner = (AbstractJavaScanner) fJavaTextTools.getStringScanner();
+  //    fJavaDocScanner = (AbstractJavaScanner) fJavaTextTools.getJavaDocScanner();
+  //    fTextEditor = editor;
+  //    fXMLTextTools = XMLPlugin.getDefault().getXMLTextTools();
+  //    xmlConfiguration = new XMLConfiguration(fXMLTextTools);
+  //  }
   /**
    * Returns the color manager for this configuration.
    * 
@@ -409,6 +411,9 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
    * (non-Javadoc) Method declared on SourceViewerConfiguration
    */
   public IAutoIndentStrategy getAutoIndentStrategy(ISourceViewer sourceViewer, String contentType) {
+    if (IPHPPartitions.PHP_PHPDOC_COMMENT.equals(contentType) 
+        || IPHPPartitions.PHP_MULTILINE_COMMENT.equals(contentType))
+      return new JavaDocAutoIndentStrategy(getConfiguredDocumentPartitioning(sourceViewer));
     if (IPHPPartitions.PHP_STRING_DQ.equals(contentType))
       return new JavaStringAutoIndentStrategyDQ(getConfiguredDocumentPartitioning(sourceViewer));
     if (IPHPPartitions.PHP_STRING_SQ.equals(contentType))
@@ -428,35 +433,37 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
   protected RuleBasedScanner getCodeScanner() {
     return fCodeScanner; //fJavaTextTools.getCodeScanner();
   }
-       /**
-        * Returns the Java multi-line comment scanner for this configuration.
-        *
-        * @return the Java multi-line comment scanner
-        * @since 2.0
-        */
-       protected RuleBasedScanner getMultilineCommentScanner() {
-               return fMultilineCommentScanner;
-       }
-       
-       /**
-        * Returns the Java single-line comment scanner for this configuration.
-        *
-        * @return the Java single-line comment scanner
-        * @since 2.0
-        */
-       protected RuleBasedScanner getSinglelineCommentScanner() {
-               return fSinglelineCommentScanner;
-       }
-       
-       /**
-        * Returns the Java string scanner for this configuration.
-        *
-        * @return the Java string scanner
-        * @since 2.0
-        */
-       protected RuleBasedScanner getStringScanner() {
-               return fStringScanner;
-       }
+
+  /**
+   * Returns the Java multi-line comment scanner for this configuration.
+   * 
+   * @return the Java multi-line comment scanner
+   * @since 2.0
+   */
+  protected RuleBasedScanner getMultilineCommentScanner() {
+    return fMultilineCommentScanner;
+  }
+
+  /**
+   * Returns the Java single-line comment scanner for this configuration.
+   * 
+   * @return the Java single-line comment scanner
+   * @since 2.0
+   */
+  protected RuleBasedScanner getSinglelineCommentScanner() {
+    return fSinglelineCommentScanner;
+  }
+
+  /**
+   * Returns the Java string scanner for this configuration.
+   * 
+   * @return the Java string scanner
+   * @since 2.0
+   */
+  protected RuleBasedScanner getStringScanner() {
+    return fStringScanner;
+  }
+
   /**
    * Returns the HTML source code scanner for this configuration.
    * 
@@ -470,10 +477,9 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
    * 
    * @return the Smarty source code scanner
    */
-//  protected RuleBasedScanner getSmartyScanner() {
-//    return fJavaTextTools.getSmartyScanner();
-//  }
-
+  //  protected RuleBasedScanner getSmartyScanner() {
+  //    return fJavaTextTools.getSmartyScanner();
+  //  }
   /*
    * @see SourceViewerConfiguration#getReconciler(ISourceViewer)
    */
@@ -575,10 +581,9 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
    * 
    * @return the SmartyDoc source code scanner
    */
-//  protected RuleBasedScanner getSmartyDocScanner() {
-//    return fJavaTextTools.getSmartyDocScanner();
-//  }
-
+  //  protected RuleBasedScanner getSmartyDocScanner() {
+  //    return fJavaTextTools.getSmartyDocScanner();
+  //  }
   /**
    * Returns the PHPDoc source code scanner for this configuration.
    * 
@@ -787,12 +792,12 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
     //    dr = new DefaultDamagerRepairer(getHTMLScanner());
     //    reconciler.setDamager(dr, IPHPPartitions.JS_MULTILINE_COMMENT);
     //    reconciler.setRepairer(dr, IPHPPartitions.JS_MULTILINE_COMMENT);
-//    DefaultDamagerRepairer phpDR = new DefaultDamagerRepairer(getSmartyScanner());
-//    phpReconciler.setDamager(phpDR, IPHPPartitions.SMARTY);
-//    phpReconciler.setRepairer(phpDR, IPHPPartitions.SMARTY);
-//    phpDR = new DefaultDamagerRepairer(getSmartyDocScanner());
-//    phpReconciler.setDamager(phpDR, IPHPPartitions.SMARTY_MULTILINE_COMMENT);
-//    phpReconciler.setRepairer(phpDR, IPHPPartitions.SMARTY_MULTILINE_COMMENT);
+    //    DefaultDamagerRepairer phpDR = new DefaultDamagerRepairer(getSmartyScanner());
+    //    phpReconciler.setDamager(phpDR, IPHPPartitions.SMARTY);
+    //    phpReconciler.setRepairer(phpDR, IPHPPartitions.SMARTY);
+    //    phpDR = new DefaultDamagerRepairer(getSmartyDocScanner());
+    //    phpReconciler.setDamager(phpDR, IPHPPartitions.SMARTY_MULTILINE_COMMENT);
+    //    phpReconciler.setRepairer(phpDR, IPHPPartitions.SMARTY_MULTILINE_COMMENT);
     //    dr = new DefaultDamagerRepairer(new SingleTokenScanner(new TextAttribute(fJavaTextTools.getColorManager().getColor(
     //        PHPColorProvider.MULTI_LINE_COMMENT))));
     //    reconciler.setDamager(dr, IPHPPartitions.HTML_MULTILINE_COMMENT);
index 3545ed0..dfe2587 100644 (file)
@@ -131,6 +131,7 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon
 
   //public static final String BUILDER_INDEX_ID = PLUGIN_ID + ".indexbuilder";
   /** General debug flag */
+  
   public static final boolean DEBUG = false;
 
   /**