/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.internal.formatter.comment; import java.util.Iterator; import java.util.ListIterator; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.wst.jsdt.internal.formatter.CodeFormatterVisitor; /** * Multi-comment region in a source code document. * * @since 3.0 */ public class MultiCommentRegion extends CommentRegion implements IJavaDocTagConstants { /** Should root tag parameter descriptions be indented after the tag? */ private final boolean fIndentDescriptions; /** Should root tag parameter descriptions be indented? */ private final boolean fIndentRoots; /** Should description of parameters go to the next line? */ private final boolean fParameterNewLine; /** Should root tags be separated from description? */ private boolean fSeparateRoots; /** * Creates a new multi-comment region. * * @param document the document which contains the comment region * @param position the position of this comment region in the document * @param formatter the given formatter */ public MultiCommentRegion(final IDocument document, final Position position, final CodeFormatterVisitor formatter) { super(document, position, formatter); fIndentRoots= this.preferences.comment_indent_root_tags; fIndentDescriptions= this.preferences.comment_indent_parameter_description; fSeparateRoots= this.preferences.comment_insert_empty_line_before_root_tags; fParameterNewLine= this.preferences.comment_insert_new_line_for_parameter; fClear = this.preferences.comment_clear_blank_lines_in_block_comment; } /* * @see org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRegion#canAppend(org.eclipse.wst.jsdt.internal.corext.text.comment.CommentLine, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange, int, int) */ protected boolean canAppend(final CommentLine line, final CommentRange previous, final CommentRange next, final int index, int count) { final boolean blank= next.hasAttribute(COMMENT_BLANKLINE); // Avoid wrapping punctuation if (next.getLength() <= 2 && !blank && isNonAlphaNumeric(next)) return true; if (fParameterNewLine && line.hasAttribute(COMMENT_PARAMETER) && line.getSize() > 1) return false; if (previous != null) { if (index != 0 && (blank || previous.hasAttribute(COMMENT_BLANKLINE) || next.hasAttribute(COMMENT_PARAMETER) || next.hasAttribute(COMMENT_ROOT) || next.hasAttribute(COMMENT_SEPARATOR) || next.hasAttribute(COMMENT_NEWLINE) || previous.hasAttribute(COMMENT_BREAK) || previous.hasAttribute(COMMENT_SEPARATOR))) return false; if (previous.hasAttribute(COMMENT_ROOT)) return true; if (next.hasAttribute(COMMENT_IMMUTABLE) && previous.hasAttribute(COMMENT_IMMUTABLE)) return true; } // always append elements that did not have any range separators if (!next.hasAttribute(COMMENT_STARTS_WITH_RANGE_DELIMITER)) { return true; } if (fIndentRoots && !line.hasAttribute(COMMENT_ROOT) && !line.hasAttribute(COMMENT_PARAMETER)) count -= stringToLength(line.getIndentationReference()); // Avoid appending consecutive immutable ranges, which together exceed the line width if (next.hasAttribute(COMMENT_IMMUTABLE) && (previous == null || !previous.hasAttribute(COMMENT_IMMUTABLE))) { // Breaking the abstraction by directly accessing the list of ranges for looking ahead Iterator iter= getRanges().iterator(); CommentRange current= null; while (iter.hasNext() && current != next) current= (CommentRange) iter.next(); if (current != null && iter.hasNext()) { try { int lineNumber= getDocument().getLineOfOffset(getOffset() + current.getOffset()); CommentRange last= current; while (iter.hasNext()) { current= (CommentRange) iter.next(); if (current.hasAttribute(COMMENT_IMMUTABLE) && getDocument().getLineOfOffset(getOffset() + current.getOffset()) == lineNumber) last= current; else break; } count -= last.getOffset() + last.getLength() - (next.getOffset() + next.getLength()); } catch (BadLocationException e) { // Should not happen } } } return super.canAppend(line, previous, next, index, count); } /* * @see org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRegion#getDelimiter(org.eclipse.wst.jsdt.internal.corext.text.comment.CommentLine, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentLine, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange, java.lang.String) */ protected String getDelimiter(CommentLine predecessor, CommentLine successor, CommentRange previous, CommentRange next, String indentation) { final String delimiter= super.getDelimiter(predecessor, successor, previous, next, indentation); if (previous != null) { // Blank line before <pre> tag if (previous.hasAttribute(COMMENT_IMMUTABLE | COMMENT_SEPARATOR) && !next.hasAttribute(COMMENT_CODE) && !successor.hasAttribute(COMMENT_BLANKLINE)) return delimiter + delimiter; // Blank line after </pre> tag else if (next.hasAttribute(COMMENT_IMMUTABLE | COMMENT_SEPARATOR) && !successor.hasAttribute(COMMENT_BLANKLINE) && !predecessor.hasAttribute(COMMENT_BLANKLINE)) return delimiter + delimiter; // Add blank line before first root/parameter tag, if "Blank line before Javadoc tags" else if (fSeparateRoots && previous.hasAttribute(COMMENT_PARAGRAPH) && !successor.hasAttribute(COMMENT_BLANKLINE) && !predecessor.hasAttribute(COMMENT_BLANKLINE)) return delimiter + delimiter; else if (fIndentRoots && !predecessor.hasAttribute(COMMENT_ROOT) && !predecessor.hasAttribute(COMMENT_PARAMETER) && !predecessor.hasAttribute(COMMENT_BLANKLINE)) return delimiter + stringToIndent(predecessor.getIndentationReference()); } return delimiter; } /* * @see org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRegion#getDelimiter(org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange, org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRange) */ protected String getDelimiter(final CommentRange previous, final CommentRange next) { // simply preserve range (~ word) breaks if (previous != null && !previous.hasAttribute(COMMENT_STARTS_WITH_RANGE_DELIMITER)) { return ""; //$NON-NLS-1$ } else { return super.getDelimiter(previous, next); } } /** * Should root tag parameter descriptions be indented after the tag? * * @return <code>true</code> iff the descriptions should be indented * after, <code>false</code> otherwise. */ protected final boolean isIndentDescriptions() { return fIndentDescriptions; } /** * Should root tag parameter descriptions be indented? * * @return <code>true</code> iff the root tags should be indented, * <code>false</code> otherwise. */ protected final boolean isIndentRoots() { return fIndentRoots; } /** * Marks the comment ranges confined by HTML ranges. */ protected void markHtmlRanges() { // Do nothing } /** * Marks the comment range with its HTML tag attributes. * * @param range the comment range to mark * @param token token associated with the comment range */ protected void markHtmlTag(final CommentRange range, final char[] token) { // Do nothing } /** * Marks the comment range with its javadoc tag attributes. * * @param range the comment range to mark * @param token token associated with the comment range */ protected void markJavadocTag(final CommentRange range, final char[] token) { range.markPrefixTag(COMMENT_ROOT_TAGS, COMMENT_TAG_PREFIX, token, COMMENT_ROOT); } /* * @see org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRegion#markRegion() */ protected void markRegion() { int count= 0; boolean paragraph= false; char[] token= null; CommentRange range= null; for (final ListIterator iterator= getRanges().listIterator(); iterator.hasNext();) { range= (CommentRange)iterator.next(); count= range.getLength(); if (count > 0) { token= getText(range.getOffset(), count).toLowerCase().toCharArray(); markJavadocTag(range, token); if (!paragraph && (range.hasAttribute(COMMENT_ROOT) || range.hasAttribute(COMMENT_PARAMETER))) { range.setAttribute(COMMENT_PARAGRAPH); paragraph= true; } markHtmlTag(range, token); } } markHtmlRanges(); } /* * @see org.eclipse.wst.jsdt.internal.corext.text.comment.CommentRegion#createLine() * @since 3.1 */ protected CommentLine createLine() { return new MultiCommentLine(this); } }