From 222944165fa341ad3113140edade2f4a0f04cc9b Mon Sep 17 00:00:00 2001 From: jsurfer Date: Fri, 8 Oct 2004 18:49:26 +0000 Subject: [PATCH] Added auto indent strategy for phpdocs and comments --- .../ui/preferences/JavaEditorPreferencePage.java | 22 +- .../ui/text/phpdoc/JavaDocAutoIndentStrategy.java | 838 ++++++++++++++++++++ .../sourceforge/phpdt/ui/PreferenceConstants.java | 3 +- .../ui/text/PHPSourceViewerConfiguration.java | 149 ++-- .../sourceforge/phpeclipse/PHPeclipsePlugin.java | 1 + 5 files changed, 929 insertions(+), 84 deletions(-) create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java index 2dfafd5..020ffd2 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java @@ -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 index 0000000..40f04d2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/phpdoc/JavaDocAutoIndentStrategy.java @@ -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, null 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 true if the javadoc line is too short, false 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 true if the line is too long, false 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= { + "", "", "", "", "" //$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 null 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; + } + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java index 95b7d94..98dccbb 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java @@ -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 Int: positive int value specifying the number of spaces per tab. *

*/ - 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 diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/PHPSourceViewerConfiguration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/PHPSourceViewerConfiguration.java index d1e9583..d5e5073 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/PHPSourceViewerConfiguration.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/PHPSourceViewerConfiguration.java @@ -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); diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java index 3545ed0..dfe2587 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java @@ -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; /** -- 1.7.1