/// <summary> /// Create a <see cref="Comment"/> with the specified text content. /// </summary> public Comment(string text, CommentFlags flags) { Text = text; _commentFlags = flags; // Default to same line for EOL comments, and separate line for regular comments SetNewLines(flags.HasFlag(CommentFlags.EOL) ? 0 : 1); }
protected internal void SetCommentFlag(CommentFlags flag, bool value) { if (value) { _commentFlags |= flag; } else { _commentFlags &= ~flag; } }
// NOTE: No parse-points are installed for comments - instead, the parser calls the // parsing constructor directly based upon the token type. This is because we // want to treat entire comments as individual tokens to preserve whitespace. /// <summary> /// Parse a <see cref="Comment"/>. /// </summary> public Comment(Parser parser, CodeObject parent) : base(parser, parent) { Token token = parser.Token; _prefixSpaceCount = (token.LeadingWhitespace.Length < byte.MaxValue ? (byte)token.LeadingWhitespace.Length : byte.MaxValue); string text = token.Text; int start; bool noSpaceAfterDelimiter; // Parse a standard '//' comment if (text.StartsWith(ParseToken)) { // Keep track of whether or not all '//' are followed by a space start = ParseToken.Length; noSpaceAfterDelimiter = (start < text.Length && text[start] != ' '); _text = text.Substring(start).TrimEnd(); if (!IsFirstOnLine) { // The comment occurred after another token on the same line - it's an EOL comment _commentFlags |= CommentFlags.EOL; parser.NextToken(true); } else { // The comment was on a line by itself - combine with following lines if they're also comments, // and they're compatible - not Doc or block comments, same # of prefix spaces, no special prefix. while (true) { int nextLine = token.LineNumber + 1; token = parser.NextToken(true); if ((token != null) && token.IsComment && token.Text.StartsWith(ParseToken) && (token.LineNumber == nextLine) && (token.LeadingWhitespace.Length == _prefixSpaceCount) && (string.IsNullOrEmpty(_text) || CheckForSpecialComment(token.Text.Substring(ParseToken.Length)) == CommentFlags.None)) { text = parser.TokenText; start = ParseToken.Length; if (start < text.Length && text[start] != ' ') { noSpaceAfterDelimiter = true; } _text += "\n" + text.Substring(start).TrimEnd(); } else { break; } } // If the comment was left-justified, set the format flag as such so that it will be displayed // at the left margin regardless of the current level of code indentation. if (_prefixSpaceCount == 0) { _formatFlags |= FormatFlags.NoIndentation; } } } else { // Parse a '/* ... */' block comment IsBlock = true; noSpaceAfterDelimiter = false; bool formatted = true; // The parser will pass through everything between the delimiters, so we have to deal with // that here by breaking it up into lines, stripping leading spaces and asterisks, and then // putting them back together. string[] lines = text.Split('\n'); for (int i = 0; i < lines.Length; ++i) { string line = lines[i]; bool hasBlockEnd = (i == lines.Length - 1 && line.EndsWith(ParseTokenBlockEnd)); if (i == 0) { start = ParseTokenBlockStart.Length; } else { // Skip leading spaces on subsequent lines up to the indent of the first line start = Math.Min(_prefixSpaceCount, StringUtil.CharCount(line, ' ', 0)); // Special format handling: Skip a leading "*" if (start < line.Length && line[start] == '*' && !(hasBlockEnd && start == line.Length - 2)) { ++start; } else if (start < line.Length - 1) { // Special format handling: Skip " *" or "\" if followed by '*' and on the last line (if not part of the ending "*/"), // or "//" (and NOT "///"), or " " (if followed by a non-space). if ((line[start] == ' ' && line[start + 1] == '*') || (line[start] == '\\' && line[start + 1] == '*' && i == lines.Length - 1)) { if (!(hasBlockEnd && start == line.Length - 3)) { start += 2; } } else if ((line[start] == '/' && line[start + 1] == '/' && (start == line.Length - 2 || line[start + 2] != '/')) || (line[start] == ' ' && line[start + 1] == ' ' && (start == line.Length - 2 || line[start + 2] != ' '))) { start += 2; formatted = false; } else { formatted = false; } } } if (start < line.Length && line[start] != ' ') { noSpaceAfterDelimiter = true; } int length = line.Length - start; if (hasBlockEnd) { length -= ParseTokenBlockEnd.Length; } _text += (i == 0 ? "" : "\n") + line.Substring(start, length).TrimEnd(); } if (!formatted) { _commentFlags |= CommentFlags.Raw; } Token nextToken = parser.NextToken(true); // If the comment occurred after another token on the same line AND it's a single line block // comment AND it's the last token on the line - it's an inline EOL comment. if (!IsFirstOnLine && lines.Length == 1 && nextToken.IsFirstOnLine) { _commentFlags |= CommentFlags.EOL; } } // If any line is missing a space after the delimiter, then set the special flag indicating that no // spaces should be displayed. Otherwise, remove one column of spaces and add it back when displayed. if (noSpaceAfterDelimiter) { NoSpaceAfterDelimiter = true; } else { RemoveSpaces(1); } SetSpecialFlags(); }
protected internal void SetSpecialFlags() { _commentFlags |= CheckForSpecialComment(_text); }