/// <summary> /// Check if the open and close tags for an XML line should be on their own lines or not. /// </summary> /// <param name="line"></param> /// <param name="indentlevel"></param> /// <returns><c>true</c> if the tags should be split, otherwise <c>false</c>.</returns> private bool TagsOnOwnLine(CommentLineXml line, int indentlevel) { // Check for splitting all root level tags. if (Settings.Default.Formatting_CommentXmlSplitAllTags && indentlevel <= 1) { return(true); } // Split if there is more than one child line. if (line.Lines.Count > 1) { return(true); } // Split if there is literal content (eg. a code tag). if (!string.IsNullOrEmpty(line.Content)) { return(true); } // Split if this is a summary tag and option to split is set. if (Settings.Default.Formatting_CommentXmlSplitSummaryTagToMultipleLines && string.Equals(line.TagName, "summary", StringComparison.OrdinalIgnoreCase)) { return(true); } // Always split on StyleCop SA1633 copyright tag. if (Settings.Default.Formatting_CommentXmlSplitSummaryTagToMultipleLines && string.Equals(line.TagName, "copyright", StringComparison.OrdinalIgnoreCase)) { return(true); } return(false); }
/// <summary> /// Formats the comment. /// </summary> public TextPoint Format() { if (!IsValid) { throw new InvalidOperationException("Cannot format comment, the comment is not valid."); } var originalText = _startPoint.GetText(_endPoint); var matches = _commentLineRegex.Matches(originalText).OfType <Match>().ToArray(); var commentOptions = new CommentOptions { Prefix = matches.First(m => m.Success).Groups["prefix"].Value ?? string.Empty, Regex = CodeCommentHelper.GetCommentRegex(_document.GetCodeLanguage(), false) }; // Concatenate the comment lines without comment prefixes and see if the resulting bit // can be parsed as XML. ICommentLine line = null; var lineTexts = matches.Select(m => m.Groups["line"].Value).ToArray(); var commentText = string.Join(Environment.NewLine, lineTexts); if (commentText.Contains('<')) { try { var xml = XElement.Parse($"<doc>{commentText}</doc>"); line = new CommentLineXml(xml); } catch (System.Xml.XmlException) { // If XML cannot be parsed, comment will be handled as a normal text comment. } } if (line == null) { line = new CommentLine(commentText); } var formatter = new CommentFormatter( line, _formatterOptions, commentOptions); if (!formatter.Equals(originalText)) { var cursor = StartPoint.CreateEditPoint(); cursor.Delete(EndPoint); cursor.Insert(formatter.ToString()); _endPoint = cursor.CreateEditPoint(); } return(EndPoint); }
/// <returns> /// Returns <c>true</c> if the line requests a break afterwards (did not fit on a single /// line), otherwise <c>false</c>. /// </returns> private bool ParseXml(CommentLineXml line, int indentLevel = 0) { // All XML lines start on a new line. if (!_isFirstWord) { NewLine(); } Indent(indentLevel); Append(line.OpenTag); // Self closing tags have no content, skip all further logic and just output. var tagOnOwnLine = TagsOnOwnLine(line, indentLevel); if (line.IsSelfClosing) { if (tagOnOwnLine) { NewLine(); return(false); } return(true); } // If this is the StyleCop SA1633 header <copyright> tag, the content should ALWAYS be // indented. So if no indenting is set, fake it. This is done by adding the indenting to // the comment prefix, otherwise it would indent recursively. var isCopyrightTag = indentLevel == 0 && string.Equals(line.TagName, "copyright", StringComparison.OrdinalIgnoreCase); if (isCopyrightTag && Settings.Default.Formatting_CommentXmlValueIndent < 1) { _commentPrefixLength += CodeCommentHelper.CopyrightExtraIndent; _commentOptions.Prefix += string.Empty.PadLeft(CodeCommentHelper.CopyrightExtraIndent); } // Increase the indent level. indentLevel++; var isLiteralContent = !string.IsNullOrEmpty(line.Content); // If true the tag should be alone on it's own line. tagOnOwnLine |= isLiteralContent; if (!tagOnOwnLine && Settings.Default.Formatting_CommentXmlSpaceTags) { Append(CodeCommentHelper.Spacer); } // If the literal content of an XML tag is set, output that content without formatting. if (isLiteralContent) { var literals = line.Content.Trim('\r', '\n').TrimEnd('\r', '\n', '\t', ' ').Split('\n'); for (int i = 0; i < literals.Length; i++) { NewLine(true); Append(literals[i].TrimEnd()); } } else { // If the tag has any child lines and should be on it's own line, put another break. if (tagOnOwnLine && line.Lines.Count > 0) { NewLine(); } // Loop and parse all content lines, with a little hacky solution for allowing the // parser to know the XML tag length. var xmlTagLength = tagOnOwnLine ? 0 : WordLength(line.OpenTag) + WordLength(line.CloseTag); var needBreakBefore = false; foreach (var l in line.Lines) { if (needBreakBefore) { NewLine(); } // Parse function returns true if it had to wrap lines. If so, we need to force a // newline before the closing tag. needBreakBefore = Parse(l, indentLevel, xmlTagLength); tagOnOwnLine |= needBreakBefore; } } indentLevel--; // Undo the indenting hack done for copyright tags. if (isCopyrightTag && Settings.Default.Formatting_CommentXmlValueIndent < 1) { _commentPrefixLength -= CodeCommentHelper.CopyrightExtraIndent; _commentOptions.Prefix = _commentOptions.Prefix.Substring(0, _commentPrefixLength); } // If opening tag was on own line, do the same for the closing tag. if (tagOnOwnLine && !_isFirstWord) { NewLine(); Indent(indentLevel); } else if (Settings.Default.Formatting_CommentXmlSpaceTags) { Append(CodeCommentHelper.Spacer); } Append(line.CloseTag); return(tagOnOwnLine || CommentLineXml.SingleLineElementNames.Contains(line.TagName, StringComparer.OrdinalIgnoreCase)); }