[260282] [formatting][preferences] Add an option to formatter to prevent formatting text within XML comments
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
index 291b4d4..255520f 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
@@ -63,6 +63,7 @@
 	static private final String XSL_ATTRIBUTE = "attribute"; //$NON-NLS-1$
 	static private final String XSL_TEXT = "text"; //$NON-NLS-1$
 	static private final String SPACE = " "; //$NON-NLS-1$
+	static private final String EMPTY = ""; //$NON-NLS-1$
 	static private final String PROPERTY_WHITESPACE_FACET = "org.eclipse.wst.xsd.cm.properties/whitespace"; //$NON-NLS-1$
 
 	private XMLFormattingPreferences fPreferences = null;
@@ -985,155 +986,135 @@
 		int lineWidth = parentConstraints.getAvailableLineWidth() - currentRegion.getFullText().length();
 		// Don't format if we're not exceeding the available line width, or if the whitespace
 		// strategy is to preserve whitespace - But update line width.
-		if(currentRegion == null ||	XMLFormattingConstraints.PRESERVE.equals(parentConstraints.getWhitespaceStrategy())) {
+		if(currentRegion == null ||	XMLFormattingConstraints.PRESERVE.equals(parentConstraints.getWhitespaceStrategy()) || !fPreferences.getFormatCommentText()) {
 			parentConstraints.setAvailableLineWidth(lineWidth);
-		} else {
-			// If there is enough room, format the start of the comment tag if it is on its own line
-			// else comment must be made into multi line and formated
-			if(lineWidth >= 0) {
-				parentConstraints.setAvailableLineWidth(lineWidth);
-				TextEdit indentEdit = this.getIndentEdit( currentRegion, parentConstraints.getIndentLevel()+1);
-				
-				if(indentEdit != null) {
-					textEdit.addChild(indentEdit);
-				}
-			} else {
-				// Iterate over each text region of the comment
-				Iterator it = currentRegion.getRegions().iterator();
-				while(it.hasNext()) {
-					ITextRegion text = (ITextRegion) it.next();
-					formatCommentTag(textEdit, parentConstraints, currentRegion, text);
-				}
+			return;
+		}
+
+		Iterator it = currentRegion.getRegions().iterator();
+		ITextRegion previous = null;
+		if (previousRegion == null)
+			previousRegion = currentRegion.getPrevious();
+		// Iterate over each text region of the comment
+		Node parent = currentDOMRegion.domNode.getParentNode();
+		while(it.hasNext()) {
+			ITextRegion text = (ITextRegion) it.next();
+			String type = text.getType();
+			if (type == DOMRegionContext.XML_COMMENT_OPEN) {
+				int indentLevel = (parent != null && parent.getNodeType() == Node.DOCUMENT_NODE) ? 0 : 1;
+				int width = formatCommentStart(textEdit, parentConstraints, indentLevel, currentRegion, previousRegion, text);
+				parentConstraints.setAvailableLineWidth(width);
 			}
+			else if (type == DOMRegionContext.XML_COMMENT_TEXT) {
+				int indentLevel = (parent != null && parent.getNodeType() == Node.DOCUMENT_NODE) ? -1 : parentConstraints.getIndentLevel();
+				formatCommentContent(textEdit, parentConstraints, indentLevel, currentRegion, previous, text);
+			}
+			previous = text;
 		}
 	}
-	
-	/**
-	 * Handles formatting various portions of an XML comment. Because the XML
-	 * Comment is considered its own document region, there are cases where
-	 * the previous region must be referred to for proper indentation
-	 * consideration. Because of this, most of the special cases are
-	 * catering to the opening text region of the document region.
-	 * 
-	 * @param textEdit
-	 * @param parentConstraints
-	 * @param currentRegion
-	 * @param region
-	 */
-	private void formatCommentTag(TextEdit textEdit, XMLFormattingConstraints parentConstraints, IStructuredDocumentRegion currentRegion, ITextRegion region) {
-		int availableLineWidth = parentConstraints.getAvailableLineWidth();
-		int indentLevel = parentConstraints.getIndentLevel() + 1;
-		boolean initialIndent = false;
-		
-		// Indent the text of the comment an additional level
-		if(DOMRegionContext.XML_COMMENT_TEXT.equals(region.getType())) {
-			indentLevel++;
-			initialIndent = true;
-		}
-		
-		int fullTextOffset = 0;
-		char[] fullTextArray = currentRegion.getFullText(region).toCharArray();
-		while (fullTextOffset < fullTextArray.length) {
-			// gather all whitespaces
-			String currLineWhitespaceRun = null;
 
-			IRegion currentLineInfo = getCurrentLineInfo(currentRegion);
-			String preRegionLineText = getPreRegionLineText(currentRegion, currentLineInfo);
-			
-			// If the region is a comment opening, the whitespace would actually come from the
-			// previous document region
-			if(DOMRegionContext.XML_COMMENT_OPEN.equals(region.getType()) && currentRegion.getPrevious() != null) {
-				currLineWhitespaceRun = getTrailingWhitespace(preRegionLineText);
-			} else {
-				currLineWhitespaceRun = getCharacterRun(fullTextArray, fullTextOffset, true);
-			}
-			
-			if (currLineWhitespaceRun.length() > 0) {
-				// offset where whitespace starts
-				int whitespaceStart = fullTextOffset;
-				// update current offset in fullText for non comment-opening regions
-				if(!DOMRegionContext.XML_COMMENT_OPEN.equals(region.getType()))
-					fullTextOffset += currLineWhitespaceRun.length();
+	private void formatCommentContent(TextEdit textEdit, XMLFormattingConstraints parentConstraints, int indentLevel, IStructuredDocumentRegion currentRegion, ITextRegion previous, ITextRegion region) {
+		int lineWidth = parentConstraints.getAvailableLineWidth() - currentRegion.getFullText(previous).length();
+		// If there's more text than line width available, format
+		String text = currentRegion.getFullText(region);
+		compressContent(textEdit, currentRegion, currentRegion.getStartOffset(region), indentLevel + 1, lineWidth, text);
+	}
 
-				// gather following word
-				String characterRun = getCharacterRun(fullTextArray, fullTextOffset, false);
-				int characterRunLength = characterRun.length();
-				if (characterRunLength > 0) {
-					// indent if word is too long or forcing initial
-					// indent
-					availableLineWidth -= characterRunLength;
-					// offset where indent/collapse will happen - for comment-opening regions,
-					// this occurs in the previous document region
-					int startOffset = 0;
+	private void compressContent(TextEdit textEdit, IStructuredDocumentRegion region, int startOffset, int indentLevel, int lineWidth, String text) {
+		int length = text.length();
+		int start = 0, end = 0;
+		char c = 0;
+		int resultLength = 0;
+		boolean joinLines = fPreferences.getJoinCommentLines();
+		boolean onOwnLine = false;
 
-					if(DOMRegionContext.XML_COMMENT_OPEN.equals(region.getType()) && currentRegion.getPrevious() != null) {
-						startOffset = currentLineInfo.getOffset();
-					} else {
-						startOffset = currentRegion.getStartOffset(region) + whitespaceStart;
+		String indent = getIndentString(indentLevel + 1);
+
+		for (int i = 0; i < length; i++) {
+			c = text.charAt(i);
+			// Compress whitespace unless its a line delimiter and formatting does not permit joining lines
+			if (Character.isWhitespace(c)) {
+				if ((c != '\r' && c!= '\n') || joinLines) {
+					// Just came off of a word
+					if (start == end) {
+						start = end = i;
 					}
-					
-					//format before the comment open
-					if((isWhitespace(preRegionLineText) && DOMRegionContext.XML_COMMENT_OPEN.equals(region.getType()))) {
-						availableLineWidth = indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, startOffset, currLineWhitespaceRun, false);
-					}
-					//format the rest of the lines of the comment
-					else if (initialIndent || (availableLineWidth <= 0)) {
-						// indent if not already indented
-						//String prevRegionWhitespaceRun  = getCharacterRun(currentRegion.getPrevious().getFullText().toCharArray(), 0, true);
-						availableLineWidth = indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, startOffset, currLineWhitespaceRun);
-						// remember to subtract word length
-						availableLineWidth -= characterRunLength;
-						// Indented the first word of the comment
-						if(initialIndent)
-							initialIndent = false;
-					}
-					else {
-						// just collapse spaces
-						startOffset = currentRegion.getStartOffset(region) - getTrailingWhitespace(preRegionLineText).length();
-						availableLineWidth = collapseSpaces(textEdit, startOffset, availableLineWidth, currLineWhitespaceRun);
-					}
-					
-					fullTextOffset += characterRunLength;
+					end++;
+					resultLength++;
 				}
 				else {
-					// handle trailing whitespace
-					int whitespaceOffset = currentRegion.getStartOffset(region) + whitespaceStart;
-					DeleteEdit deleteTrailing = new DeleteEdit(whitespaceOffset, currLineWhitespaceRun.length());
-					textEdit.addChild(deleteTrailing);
+					// correct the indent of this line
+					lineWidth = fPreferences.getMaxLineWidth();
+					resultLength = 0;
+					onOwnLine = true;
+
+					// Compress any whitespace before the line delimiter
+					if (start != end) {
+						int replaceLength = end - start;
+						textEdit.addChild(new ReplaceEdit(start + startOffset, replaceLength, EMPTY));
+						start = end = i;
+					}
 				}
 			}
 			else {
-				// gather word
-				String characterRun = getCharacterRun(fullTextArray, fullTextOffset, false);
-				int characterRunLength = characterRun.length();
-				if (characterRunLength > 0) {
-					// indent if word is too long or forcing initial
-					// indent
-					availableLineWidth = availableLineWidth - characterRunLength;
-
-					//format before the comment open
-					if(isWhitespace(preRegionLineText) && DOMRegionContext.XML_COMMENT_OPEN.equals(region.getType())) {
-						availableLineWidth= indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, currentRegion.getStartOffset(region), currLineWhitespaceRun, false);
+				// Transitioned to a new word
+				if (start != end) {
+					int replaceLength = end - start;
+					if (onOwnLine) {
+						// If content is on its own line, replace leading whitespace with proper indent
+						textEdit.addChild(new ReplaceEdit(start + startOffset, replaceLength, indent));
+						resultLength -= (replaceLength - indent.length());
+						onOwnLine = false;
 					}
-					//format the rest of the lines of the comment
-					else if ((DOMRegionContext.XML_COMMENT_CLOSE.equals(region.getType())) || initialIndent || (DOMRegionContext.XML_COMMENT_TEXT.equals(region.getType()) && availableLineWidth <= 0)) {
-						// indent if not already indented
-						availableLineWidth = indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, currentRegion.getStartOffset(region), currLineWhitespaceRun);
-						// remember to subtract word length
-						availableLineWidth -= characterRunLength;
-						if(initialIndent)
-							initialIndent = false;
+					else if (!(replaceLength == 1 && text.charAt(start) == ' ')) {
+						textEdit.addChild(new ReplaceEdit(start + startOffset, replaceLength, SPACE));
+						resultLength -= (replaceLength - 1);
 					}
-					else {
-						// just collapse spaces
-						availableLineWidth -= characterRunLength;
+					start = end = i;
+					// Make sure the word starts on a new line
+					if (resultLength > lineWidth) {
+						lineWidth = fPreferences.getMaxLineWidth();
+						resultLength = 0;
+						textEdit.addChild(new InsertEdit(start + startOffset, getLineDelimiter(region) + indent));
 					}
-					fullTextOffset += characterRunLength;
 				}
+				// Word is immediately after line delimiters, indent appropriately
+				if (onOwnLine) {
+					textEdit.addChild(new InsertEdit(i + startOffset, indent));
+					onOwnLine = false;
+				}
+				resultLength++;
 			}
 		}
-		// update available line width
-		parentConstraints.setAvailableLineWidth(availableLineWidth);
+
+		// Clean up any dangling whitespace
+		int replaceLength = end - start;
+		indent = getIndentString(indentLevel);
+		if (replaceLength == 0) { // No trailing whitespace
+			textEdit.addChild(new InsertEdit(length + startOffset, (onOwnLine) ? indent : SPACE));
+		}
+		else {
+			String whitespace = text.substring(start);
+			String replacement = (onOwnLine) ? indent : SPACE;
+			if (!whitespace.equals(replacement)) {
+				textEdit.addChild(new ReplaceEdit(start + startOffset, replaceLength, replacement));
+			}
+		}
+	}
+
+	private int formatCommentStart(TextEdit textEdit, XMLFormattingConstraints parentConstraints, int indentLevel, IStructuredDocumentRegion currentRegion, IStructuredDocumentRegion previousRegion, ITextRegion region) {
+		int lineWidth = parentConstraints.getAvailableLineWidth();
+		if (previousRegion.getType() == DOMRegionContext.XML_CONTENT) {
+			String previousText = previousRegion.getFullText();
+			String trailingWhitespace = getTrailingWhitespace(previousText);
+			String delimiters = extractLineDelimiters(trailingWhitespace, previousRegion);
+			if (delimiters != null && delimiters.length() > 0){// && previousText.length() == trailingWhitespace.length()) {
+				// Format the comment if it's on a new line
+				int offset = previousRegion.getEnd() - trailingWhitespace.length();
+				lineWidth = indentIfNotAlreadyIndented(textEdit, currentRegion, parentConstraints.getIndentLevel() + indentLevel, offset, trailingWhitespace);
+			}
+		}
+		return lineWidth;
 	}
 
 	/**
@@ -1185,85 +1166,6 @@
 		}
 		return indentString.toString();
 	}
-	
-	/**
-	 * @param currentRegion the region to indent
-	 * @param indentLevel the level to indent the region to
-	 * @return a <code>TextEdit</code> that will indent the given region to the given indentLevel
-	 */
-	private TextEdit getIndentEdit(IStructuredDocumentRegion currentRegion, int indentLevel) {
-		ReplaceEdit indentEdit = null;
-		
-		IRegion currentLineInfo = getCurrentLineInfo(currentRegion);
-		if(currentLineInfo != null) {
-			String preRegionLineText = getPreRegionLineText(currentRegion, currentLineInfo);
-			int lineOffset = currentLineInfo.getOffset();
-			
-			//if previous region is all whitespace then we need to format it
-			//else only need to format on this line
-			IStructuredDocumentRegion previousRegion = currentRegion.getPrevious();
-			if(DOMRegionContext.XML_CONTENT.equals(previousRegion.getType()) && isWhitespace(previousRegion.getFullText())) {
-				String delimiters = extractLineDelimiters(previousRegion.getFullText(), previousRegion);
-				
-				// keep blank lines preceding comment but remove any other whitespace from them
-				if(delimiters != null && delimiters.length() > 0) {
-					indentEdit = new ReplaceEdit(previousRegion.getStartOffset(),
-						previousRegion.getLength(), delimiters + getIndentString(indentLevel));
-				}
-			} else {
-				// indent the comment only if its on a newline with only whitespace before it
-				int preRegionLineLength = -1;
-				if(lineOffset == currentRegion.getStartOffset()) {
-					preRegionLineLength = 0;
-				} else if(isWhitespace(preRegionLineText)) {
-					preRegionLineLength = preRegionLineText.length();
-				}
-				
-				if(preRegionLineLength != -1) {
-					indentEdit = new ReplaceEdit(lineOffset, preRegionLineLength,
-						getIndentString(indentLevel));
-				}
-			}
-		}
-		
-		return indentEdit;
-	}
-	
-	/**
-	 * @param currentRegion the region to get the line info for
-	 * @return the line information for the line that the given region starts on
-	 */
-	private IRegion getCurrentLineInfo(IStructuredDocumentRegion currentRegion) {
-		IRegion currentLineInfo = null;
-		
-		try {
-			IStructuredDocument doc = currentRegion.getParentDocument();
-			currentLineInfo = doc.getLineInformationOfOffset(currentRegion.getStart());
-		} catch (BadLocationException e) {
-			Logger.logException("This should never happen", e);
-		}
-		
-		return currentLineInfo;
-	}
-	
-	/**
-	 * @param currentRegion the current region
-	 * @param currentLineInfo the line info for the current regions start line
-	 * @return the text that appears on the first line that the given current region is on up until the current region starts
-	 */
-	private String getPreRegionLineText(IStructuredDocumentRegion currentRegion, IRegion currentLineInfo) {
-		String preRegionLineText = "";
-		
-		try {
-			int lineOffset = currentLineInfo.getOffset();
-			int preRegionLineLength = currentRegion.getStartOffset()-lineOffset;
-			preRegionLineText = currentRegion.getParentDocument().get(lineOffset, preRegionLineLength);
-		} catch (BadLocationException e) {
-			Logger.logException("This should never happen", e);
-		}
-		
-		return preRegionLineText;
-	}
 
 	protected XMLFormattingPreferences getFormattingPreferences() {
 		if (fPreferences == null)
@@ -1274,41 +1176,23 @@
 	protected void setFormattingPreferences(XMLFormattingPreferences preferences) {
 		fPreferences = preferences;
 	}
-	
-	/**
-	 * Indent if whitespaceRun does not already contain an indent
-	 * 
-	 * @param textEdit
-	 * @param currentRegion
-	 * @param indentLevel
-	 * @param indentStartOffset
-	 * @param whitespaceRun
-	 * @return
-	 */
-	private int indentIfNotAlreadyIndented(TextEdit textEdit, IStructuredDocumentRegion currentRegion, int indentLevel, int indentStartOffset, String whitespaceRun) {
-		return indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, indentStartOffset, whitespaceRun, true);
-	}
 
 	/**
 	 * Indent if whitespaceRun does not already contain an indent
 	 * 
 	 * @param textEdit
-	 * @param currentRegion
 	 * @param indentLevel
 	 * @param indentStartOffset
+	 * @param maxAvailableLineWidth
 	 * @param whitespaceRun
-	 * @param checkForLineDelim
-	 * @return
+	 * @return new available line width up to where indented
 	 */
-	private int indentIfNotAlreadyIndented(TextEdit textEdit, IStructuredDocumentRegion currentRegion, int indentLevel, int indentStartOffset, String whitespaceRun, boolean checkForLineDelim) {
+	private int indentIfNotAlreadyIndented(TextEdit textEdit, IStructuredDocumentRegion currentRegion, int indentLevel, int indentStartOffset, String whitespaceRun) {
 		int maxAvailableLineWidth = getFormattingPreferences().getMaxLineWidth();
 
 		int availableLineWidth;
 		String indentString = getIndentString(indentLevel);
-		String lineDelimiter = "";
-		if(checkForLineDelim) {
-			lineDelimiter = getLineDelimiter(currentRegion);
-		}
+		String lineDelimiter = getLineDelimiter(currentRegion);
 		String newLineAndIndent = lineDelimiter + indentString;
 		
 		TextEdit indentation = null;
@@ -1796,15 +1680,4 @@
 	void setProgressMonitor(IProgressMonitor monitor) {
 		fProgressMonitor = monitor;
 	}
-
-	private static boolean isWhitespace(String s) {
-		if(s != null) {
-			for (int i = 0; i < s.length(); i++) {
-				if (!Character.isWhitespace(s.charAt(i))) {
-					return false;
-				}
-			}
-		}
-		return true;
-	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingPreferences.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingPreferences.java
index 78711d9..61c1b46 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingPreferences.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingPreferences.java
@@ -27,6 +27,9 @@
 	private boolean fAlignFinalBracket = false;
 	private boolean fSpaceBeforeEmptyCloseTag = true;
 	private boolean fIndentMultipleAttributes = false;
+	private boolean fFormatCommentText = true;
+	private boolean fJoinCommentLines = false;
+
 	private String fPCDataWhitespaceStrategy = XMLFormattingConstraints.PRESERVE;
 	private String fTextIndentStrategy = XMLFormattingConstraints.INLINE;
 	private String fTextWhitespaceStrategy = XMLFormattingConstraints.COLLAPSE;
@@ -40,6 +43,9 @@
 	public XMLFormattingPreferences() {
 		Preferences preferences = XMLCorePlugin.getDefault().getPluginPreferences();
 		if (preferences != null) {
+			setFormatCommentText(preferences.getBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_TEXT));
+			setJoinCommentLines(preferences.getBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_JOIN_LINES));
+
 			setMaxLineWidth(preferences.getInt(XMLCorePreferenceNames.LINE_WIDTH));
 			setIndentMultipleAttributes(preferences.getBoolean(XMLCorePreferenceNames.SPLIT_MULTI_ATTRS));
 			setAlignFinalBracket(preferences.getBoolean(XMLCorePreferenceNames.ALIGN_END_BRACKET));
@@ -71,6 +77,10 @@
 		return fMaxLineWidth;
 	}
 
+	public boolean getFormatCommentText() {
+		return fFormatCommentText;
+	}
+
 	public boolean getAlignFinalBracket() {
 		return fAlignFinalBracket;
 	}
@@ -103,6 +113,18 @@
 		return fElementWhitespaceStrategy;
 	}
 	
+	public boolean getJoinCommentLines() {
+		return fJoinCommentLines;
+	}
+
+	public void setJoinCommentLines(boolean joinCommentLines) {
+		fJoinCommentLines = joinCommentLines;
+	}
+
+	public void setFormatCommentText(boolean formatCommentText) {
+		fFormatCommentText = formatCommentText;
+	}
+
 	public void setSpaceBeforeEmptyCloseTag(boolean spaceBeforeEmptyCloseTag) {
 		fSpaceBeforeEmptyCloseTag = spaceBeforeEmptyCloseTag;
 	}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceInitializer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceInitializer.java
index 1a2e2c1..50fb82b 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceInitializer.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceInitializer.java
@@ -39,7 +39,8 @@
 		node.putBoolean(XMLCorePreferenceNames.ALIGN_END_BRACKET, false);
 		node.putBoolean(XMLCorePreferenceNames.PRESERVE_CDATACONTENT, false);
 		node.putBoolean(XMLCorePreferenceNames.SPACE_BEFORE_EMPTY_CLOSE_TAG, true);
-		
+		node.putBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_TEXT, true);
+		node.putBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_JOIN_LINES, true);
 		// cleanup preferences
 		node.putBoolean(XMLCorePreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS, true);
 		node.putBoolean(XMLCorePreferenceNames.INSERT_REQUIRED_ATTRS, true);
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceNames.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceNames.java
index 0bd4df2..e03ae53 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceNames.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/preferences/XMLCorePreferenceNames.java
@@ -231,4 +231,20 @@
      * 
      */
     public static final String HONOUR_ALL_SCHEMA_LOCATIONS = "honourAllSchemaLocations";//$NON-NLS-1$
+
+    /**
+     * Indicates whether or not the content of comments should be formatted
+     * <p>
+     * Value is of type <code>boolean</code><br />
+     * Possible values: {TRUE, FALSE}
+     * </p>
+     */
+    public static final String FORMAT_COMMENT_TEXT = "formatCommentText"; //$NON-NLS-1$
+
+    /**
+     * Indicates whether or not the lines of comments should be joined when formatting
+     * <p>
+     * Value is of type <code>boolean</code>
+     */
+    public static final String FORMAT_COMMENT_JOIN_LINES = "formatCommentJoinLines"; //$NON-NLS-1$
 }
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIMessages.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIMessages.java
index f87f274..5e73ef8 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIMessages.java
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIMessages.java
@@ -235,6 +235,8 @@
 	public static String Indentation_size;
 	public static String Indentation_size_tip;
 	public static String Clear_all_blank_lines_UI_;
+	public static String Format_comments;
+	public static String Format_comments_join_lines;
 	public static String Grammar_Constraints;
 	public static String Use_inferred_grammar_in_absence_of;
 	public static String Suggestion_Strategy;
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIPluginResources.properties b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIPluginResources.properties
index c1747b3..2309202 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIPluginResources.properties
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/XMLUIPluginResources.properties
@@ -267,6 +267,8 @@
 Indentation_size=In&dentation size:
 Indentation_size_tip=Indentation size
 Clear_all_blank_lines_UI_=Clear all &blank lines
+Format_comments=&Format comments
+Format_comments_join_lines=&Join lines
 Grammar_Constraints=Grammar Constraints
 Use_inferred_grammar_in_absence_of=&Use inferred grammar in absence of DTD/Schema
 Suggestion_Strategy=&Suggestion strategy:
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/preferences/XMLSourcePreferencePage.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/preferences/XMLSourcePreferencePage.java
index 8ced8d7..9c89244 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/preferences/XMLSourcePreferencePage.java
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/preferences/XMLSourcePreferencePage.java
@@ -62,6 +62,8 @@
 	private Spinner fIndentationSize;
 	private Button fPreservePCDATAContent;
 	private Button fAlignEndBracket;
+	private Button fFormatComments;
+	private Button fFormatCommentsJoinLines;
 	// BUG195264 - Support for removing/adding a space before empty close tags
 	private Button fSpaceBeforeEmptyCloseTag;
 
@@ -125,6 +127,14 @@
 		((GridData) fPreservePCDATAContent.getLayoutData()).horizontalSpan = 2;
 		fClearAllBlankLines = createCheckBox(formattingGroup, XMLUIMessages.Clear_all_blank_lines_UI_);
 		((GridData) fClearAllBlankLines.getLayoutData()).horizontalSpan = 2;
+		// formatting comments
+		fFormatComments = createCheckBox(formattingGroup, XMLUIMessages.Format_comments);
+		((GridData) fFormatComments.getLayoutData()).horizontalSpan = 2;
+		fFormatComments.addSelectionListener(this);
+		fFormatCommentsJoinLines = createCheckBox(formattingGroup, XMLUIMessages.Format_comments_join_lines);
+		((GridData) fFormatCommentsJoinLines.getLayoutData()).horizontalSpan = 2;
+		((GridData) fFormatCommentsJoinLines.getLayoutData()).horizontalIndent = 20;
+		// end formatting comments
 		fSpaceBeforeEmptyCloseTag = createCheckBox(formattingGroup, XMLUIMessages.Space_before_empty_close_tag);
 		((GridData) fSpaceBeforeEmptyCloseTag.getLayoutData()).horizontalSpan = 2;
 
@@ -180,6 +190,9 @@
 				fAutoProposeText.setEnabled(false);
 			}
 		}
+		if (fFormatComments != null && fFormatCommentsJoinLines != null) {
+			fFormatCommentsJoinLines.setEnabled(fFormatComments.getSelection());
+		}
 	}
 
 	protected Preferences getModelPreferences() {
@@ -226,7 +239,9 @@
 		fClearAllBlankLines.setSelection(getModelPreferences().getBoolean(XMLCorePreferenceNames.CLEAR_ALL_BLANK_LINES));
 		fPreservePCDATAContent.setSelection(getModelPreferences().getBoolean(XMLCorePreferenceNames.PRESERVE_CDATACONTENT));
 		fSpaceBeforeEmptyCloseTag.setSelection(getModelPreferences().getBoolean(XMLCorePreferenceNames.SPACE_BEFORE_EMPTY_CLOSE_TAG));
-		
+		fFormatComments.setSelection(getModelPreferences().getBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_TEXT));
+		fFormatCommentsJoinLines.setSelection(getModelPreferences().getBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_JOIN_LINES));
+
 		if (XMLCorePreferenceNames.TAB.equals(getModelPreferences().getString(XMLCorePreferenceNames.INDENTATION_CHAR))) {
 			fIndentUsingTabs.setSelection(true);
 			fIndentUsingSpaces.setSelection(false);
@@ -276,7 +291,9 @@
 		fPreservePCDATAContent.setSelection(getModelPreferences().getDefaultBoolean(XMLCorePreferenceNames.PRESERVE_CDATACONTENT));
 		// BUG195264 - Support for removing/adding a space before empty close tags
 		fSpaceBeforeEmptyCloseTag.setSelection(getModelPreferences().getDefaultBoolean(XMLCorePreferenceNames.SPACE_BEFORE_EMPTY_CLOSE_TAG));
-		
+		fFormatComments.setSelection(getModelPreferences().getDefaultBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_TEXT));
+		fFormatCommentsJoinLines.setSelection(getModelPreferences().getDefaultBoolean(XMLCorePreferenceNames.FORMAT_COMMENT_JOIN_LINES));
+
 		if (XMLCorePreferenceNames.TAB.equals(getModelPreferences().getDefaultString(XMLCorePreferenceNames.INDENTATION_CHAR))) {
 			fIndentUsingTabs.setSelection(true);
 			fIndentUsingSpaces.setSelection(false);
@@ -338,7 +355,9 @@
 		getModelPreferences().setValue(XMLCorePreferenceNames.PRESERVE_CDATACONTENT, fPreservePCDATAContent.getSelection());
 		// BUG195264 - Support for removing/adding a space before empty close tags
 		getModelPreferences().setValue(XMLCorePreferenceNames.SPACE_BEFORE_EMPTY_CLOSE_TAG, fSpaceBeforeEmptyCloseTag.getSelection());
-		
+		getModelPreferences().setValue(XMLCorePreferenceNames.FORMAT_COMMENT_TEXT, fFormatComments.getSelection());
+		getModelPreferences().setValue(XMLCorePreferenceNames.FORMAT_COMMENT_JOIN_LINES, fFormatCommentsJoinLines.getSelection());
+
 		if (fIndentUsingTabs.getSelection()) {
 			getModelPreferences().setValue(XMLCorePreferenceNames.INDENTATION_CHAR, XMLCorePreferenceNames.TAB);
 		}