/// <summary> /// Parses the given document to find all tags between the beginning of the document and the specified /// end line. /// </summary> /// <remarks> /// The <paramref name="p_pctCompleteTagCallback" /> is called whenever a complete tag has been parsed. /// A complete tag is a tag whose opening and closing tags have been found (for example, <b>..</b>). /// The stack that is returned contains all the unclosed tags found, and so represents where in the /// document heirarchy the line falls. /// </remarks> /// <param name="p_docDocument">The document to parse.</param> /// <param name="p_intEndLine">The line of the document at which to stop parsing.</param> /// <param name="p_pctCompleteTagCallback">The method to call whenever a complete tag is parsed.</param> /// <returns>A stack containing all the unclosed tags found.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown if <paramref name="p_intEndLine" /> is greater than /// or equal to the <see cref="IDocument.TotalNumberOfLines" /> of <paramref name="p_docDocument" />. /// </exception> public static TagStack ParseTags(IDocument p_docDocument, Int32 p_intEndLine, ParsedTag p_pctCompleteTagCallback, ParsedTag p_pctUnclosedTagCallback) { if (p_intEndLine >= p_docDocument.TotalNumberOfLines) { throw new ArgumentOutOfRangeException("p_intEndLine", p_intEndLine, "The given end line paramater is outside of the range of lines in the given document."); } //parse the buffer var stkTags = new TagStack(); for (var i = 0; i <= p_intEndLine; i++) { var strLine = p_docDocument.GetText(p_docDocument.GetLineSegment(i)); var intLineNum = i; var intLastOpenPos = strLine.LastIndexOf('<'); if (intLastOpenPos < 0) { continue; } var intLastClosePos = strLine.LastIndexOf('>'); if ((intLastClosePos > -1) && (intLastOpenPos > intLastClosePos)) { var stbLines = new StringBuilder(strLine); //there is an open tag on this line - read lines until it is closed. for (; i <= p_intEndLine; i++) { var strNextLine = p_docDocument.GetText(p_docDocument.GetLineSegment(i)); intLastClosePos = strLine.LastIndexOf('>'); stbLines.Append(strNextLine); if (intLastClosePos < 0) { i--; break; } } strLine = stbLines.ToString(); } var mclLineTags = rgxTagContents.Matches(strLine); foreach (Match mtcTag in mclLineTags) { var strTag = mtcTag.Groups[1].Value.Trim(); var strTagName = rgxTagName.Match(strTag).Groups[1].Value; if (strTag.StartsWith("/")) { if (stkTags.Contains(strTagName)) { while (!stkTags.Peek().Equals(strTagName)) { var tpsTag = stkTags.Pop(); var tlcStart = new TextLocation(tpsTag.Column, tpsTag.LineNumber); var tlcEnd = new TextLocation(tpsTag.Column + tpsTag.Name.Length, tpsTag.LineNumber); if (p_pctUnclosedTagCallback != null) { p_pctUnclosedTagCallback(p_docDocument, tpsTag.Name, tlcStart, tlcEnd); } } var tpsCompleteTag = stkTags.Pop(); if (p_pctCompleteTagCallback != null) { var tlcStart = new TextLocation(tpsCompleteTag.Column, tpsCompleteTag.LineNumber); var intEndFoldPos = mtcTag.Groups[1].Index; var tlcEnd = new TextLocation(intEndFoldPos, intLineNum); p_pctCompleteTagCallback(p_docDocument, strTagName, tlcStart, tlcEnd); } } } else { if (!strTag.EndsWith("/")) { stkTags.Push(strTagName, intLineNum, mtcTag.Groups[1].Index); } } } } return(stkTags); }