/* Function: Parse * Parses the passed comment for documentation. If successful it will return true and add <Topics> to the list. */ public bool Parse(PossibleDocumentationComment comment, int languageID, List <Topic> topics) { // Apply to all comments, not just Natural Docs'. Javadoc comments may use a left line of stars which would // need to be taken out. LineFinder.MarkTextBoxes(comment); // First try Natural Docs while requiring a header. If the first line is a header it's treated as Natural Docs content // regardless of comment style. if (naturalDocsParser.Parse(comment, languageID, topics, true) == true) { return(true); } // Next try Javadoc. We test this before XML so it's not mistaken for it if it starts with a HTML tag. if (comment.Javadoc && javadocParser.Parse(comment, topics) == true) { return(true); } // Next try XML. XML can actually use the Javadoc comment style as well. if ((comment.XML || comment.Javadoc) && xmlParser.Parse(comment, topics) == true) { return(true); } // If neither of them were able to parse it, we can assume comments using the XML or Javadoc styles are headerless // Natural Docs comments. if ((comment.Javadoc || comment.XML) && naturalDocsParser.Parse(comment, languageID, topics, false) == true) { return(true); } return(false); }
/* Function: MarkTextBoxes * * Finds all text boxes in a comment and marks their tokens as <Tokenization.CommentParsingType.CommentDecoration>. * Vertical lines will only be detected if they are continuous throughout the comment and horizontal lines if they * are connected to it. Freestanding horizontal lines are *not* detected here. This function tolerates differing * symbols on corners and where embedded horizontal lines connect to the vertical. It also tolerates tokens * marked with <Tokenization.CommentParsingType.CommentSymbol> differing. * * Examples: * * The box below will be marked completely, including the middle horizontal line. * * > // +----------+ * > // | Title | * > // +----------+ * > // | Text | * > // +----------+ * * The middle horizontal line below will not be marked, because it is not attached. * * > // +----------+ * > // | Title | * > // | -------- | * > // | Text | * > // +----------+ * * Nor will the horizontal line below since there is no vertical. * * > // Title * > // ---------- * > // Text * * Freestanding horizontal lines are not detected because they may be intended literally, such as when part of * a code section. If you're not in such a section use <IsHorizontalLine()> before parsing a line to filter it out. * * > // (start code) * > // +-----+ * > // | box | * > // +-----+ * > // (end code) */ public static void MarkTextBoxes(PossibleDocumentationComment comment) { char symbolA, symbolB, symbolC; int symbolACount, symbolBCount, symbolCCount; char leftSymbol = '\0'; char rightSymbol = '\0'; int leftSymbolCount = 0; int rightSymbolCount = 0; bool symbolIsAloneOnLine = false; bool testedForVerticalLines = false; LineIterator line = comment.Start; TokenIterator lineStart, lineEnd; // This should be okay to use since line numbers start at one. IDObjects.NumberSet horizontalLines = new IDObjects.NumberSet(); // Skip leading blank lines since it's okay if they're not part of the text box. while (line < comment.End && line.IsEmpty(LineBoundsMode.CommentContent)) { line.Next(); } while (line < comment.End && line.IsEmpty(LineBoundsMode.CommentContent) == false) { line.GetBounds(LineBoundsMode.ExcludeWhitespace, out lineStart, out lineEnd); // Shrink the line to exclude its comment symbols, if any. We didn't do this using the line bounds mode because // we need to know whether there was any whitespace between them and any horizontal lines. bool commentSymbolWithoutWhitespaceAtStart = false; bool commentSymbolWithoutWhitespaceAtEnd = false; if (lineStart.CommentParsingType == CommentParsingType.CommentSymbol) { commentSymbolWithoutWhitespaceAtStart = true; do { lineStart.Next(); }while (lineStart.CommentParsingType == CommentParsingType.CommentSymbol); if (lineStart.FundamentalType == FundamentalType.Whitespace) { commentSymbolWithoutWhitespaceAtStart = false; do { lineStart.Next(); }while (lineStart.FundamentalType == FundamentalType.Whitespace); } } lineEnd.Previous(); if (lineEnd.CommentParsingType == CommentParsingType.CommentSymbol) { commentSymbolWithoutWhitespaceAtEnd = true; do { lineEnd.Previous(); }while (lineEnd.CommentParsingType == CommentParsingType.CommentSymbol); if (lineEnd.FundamentalType == FundamentalType.Whitespace) { commentSymbolWithoutWhitespaceAtEnd = false; do { lineEnd.Previous(); }while (lineEnd.FundamentalType == FundamentalType.Whitespace); } } lineEnd.Next(); // Horizontal line detection bool isHorizontalLine = false; CountSymbolLine(ref lineStart, lineEnd, out symbolA, out symbolB, out symbolC, out symbolACount, out symbolBCount, out symbolCCount); if (commentSymbolWithoutWhitespaceAtStart == true && commentSymbolWithoutWhitespaceAtEnd == true && symbolACount >= 4 && symbolBCount == 0) { isHorizontalLine = true; } else if (commentSymbolWithoutWhitespaceAtStart == true && symbolACount >= 4 && (symbolBCount == 0 || (symbolBCount <= 3 && symbolCCount == 0))) { isHorizontalLine = true; } else if (commentSymbolWithoutWhitespaceAtEnd == true && ((symbolACount >= 1 && symbolACount <= 3 && symbolBCount >= 4 && symbolCCount == 0) || (symbolACount >= 4 && symbolBCount == 0))) { isHorizontalLine = true; } else if ((symbolACount >= 4 && symbolBCount == 0) || (symbolACount >= 1 && symbolACount <= 3 && symbolBCount >= 4 && symbolCCount <= 3)) { isHorizontalLine = true; } // The horizontal line has to be the only thing on the line to count. if (isHorizontalLine && lineStart == lineEnd) { horizontalLines.Add(line.LineNumber); } // Vertical line detection else if (testedForVerticalLines == false) { // We permit the very first line to be different to allow for this: // /** text // * text // */ // // However, don't skip the first line if it's a one line comment or we wouldn't be able to handle this: // ### text // if (line != comment.Start || (comment.End.LineNumber - comment.Start.LineNumber) == 1) { if (CountEdgeSymbols(line, out leftSymbol, out rightSymbol, out leftSymbolCount, out rightSymbolCount, out symbolIsAloneOnLine) == false) { return; } testedForVerticalLines = true; } } else // testedForVerticalLines == true { char lineLeftSymbol, lineRightSymbol; int lineLeftSymbolCount, lineRightSymbolCount; bool lineSymbolIsAloneOnLine; CountEdgeSymbols(line, out lineLeftSymbol, out lineRightSymbol, out lineLeftSymbolCount, out lineRightSymbolCount, out lineSymbolIsAloneOnLine); // Account for a lone symbol being the right symbol. if (lineSymbolIsAloneOnLine == true && symbolIsAloneOnLine == false && leftSymbolCount == 0 && rightSymbolCount > 0) { if (lineLeftSymbol != rightSymbol || lineLeftSymbolCount != rightSymbolCount) { return; } } else if (lineSymbolIsAloneOnLine == false && symbolIsAloneOnLine == true && lineLeftSymbolCount == 0 && lineRightSymbolCount > 0) { if (lineRightSymbol != leftSymbol || lineRightSymbolCount != leftSymbolCount) { return; } rightSymbol = leftSymbol; leftSymbol = '\0'; rightSymbolCount = leftSymbolCount; leftSymbolCount = 0; } // Otherwise it's okay to do a straight compare. else { if (lineLeftSymbol != leftSymbol || lineLeftSymbolCount != leftSymbolCount) { leftSymbol = '\0'; leftSymbolCount = 0; } if (lineRightSymbol != rightSymbol || lineRightSymbolCount != rightSymbolCount) { rightSymbol = '\0'; rightSymbolCount = 0; } if (leftSymbolCount == 0 && rightSymbolCount == 0) { return; } } // Turn off the overall alone flag if this line didn't have it. if (lineSymbolIsAloneOnLine == false) { symbolIsAloneOnLine = false; } } line.Next(); } // If we stopped because we hit a blank line, this comment is only acceptable for marking text boxes if all the lines // left are blank. while (line < comment.End && line.IsEmpty(LineBoundsMode.CommentContent)) { line.Next(); } if (line != comment.End) { return; } // If we made it this far without returning it means we have a valid text box which we have to mark as comment decoration. line = comment.Start; while (line < comment.End) { line.GetBounds(LineBoundsMode.CommentContent, out lineStart, out lineEnd); if (horizontalLines.Contains(line.LineNumber)) { while (lineStart < lineEnd) { lineStart.CommentParsingType = CommentParsingType.CommentDecoration; lineStart.Next(); } } else if (lineEnd > lineStart) { // We test the characters against the symbols to account for any exceptions we allowed to go through // in previous code. for (int i = 0; i < leftSymbolCount; i++) { if (lineStart.Character == leftSymbol) { lineStart.CommentParsingType = CommentParsingType.CommentDecoration; lineStart.Next(); } } lineEnd.Previous(); for (int i = 0; i < rightSymbolCount; i++) { if (lineEnd.Character == rightSymbol) { lineEnd.CommentParsingType = CommentParsingType.CommentDecoration; lineEnd.Previous(); } } } line.Next(); } }