public void AddItem(ParagraphLineItem item) { _items.Add(item); }
IEnumerable <ParagraphLine> readLines() { // We're processing "blocks" out of the lexer. Blocks are either: // - xml tags - these will always come in as a single block // - slabs of text - these will come one per line (but they may have a tag breaking up two slabs on the one line). // // We need to break them into what we think the lines should be. // Start reading blocks from the lexer ParagraphLine paragraphLine = new ParagraphLine(); foreach (string block in _xmlBlockLexer) { // Create a new item to put this block into. ParagraphLineItem item = new ParagraphLineItem(); // If the block is a code or "c" block then we treat the block as a single, non-reflowable chunk. if (block.StartsWith("<code") || block.StartsWith("<c") || block.StartsWith("<see") || block.StartsWith("<paramref") || block.StartsWith("<typeparamref")) { item.Text = block; item.ItemType = ItemType.NonReflowableBlock; paragraphLine.AddItem(item); } // If the block is some other xml tag then treat it as a line (we may compress these again later). else if (block.StartsWith("<")) { /* * // Yield the previous line * yield return paragraphLine; * * // Create a new line * paragraphLine = new ParagraphLine(); */ // And add the new tag into it item.Text = block; item.ItemType = ItemType.XmlElement; paragraphLine.AddItem(item); /* * // Yield that * yield return paragraphLine; * * // Create a new line * paragraphLine = new ParagraphLine(); */ } // Otherwise it must be a text block so deal with that. else { // Split the text block into lines string[] lines = block.Replace("\r", "").Split('\n'); // Process each line for (int i = 0; i < lines.Length; i++) { // Create an item for this line string line = lines[i]; item.Text = line; item.ItemType = line.Trim().Length == 0 ? ItemType.XmlSpace : ItemType.Text; paragraphLine.AddItem(item); // If we're not the last line then yield this line (last line may contain other sections). if (i != lines.Length - 1) { yield return(paragraphLine); item = new ParagraphLineItem(); paragraphLine = new ParagraphLine(); } } } } if (paragraphLine.Items.Count > 0) { yield return(paragraphLine); } }
public string ReflowToLineLength(IEnumerable <Paragraph> paragraphs, int maxLineLength) { LineBuilder lb = new LineBuilder(); bool firstParagraph = true; foreach (Paragraph paragraph in paragraphs) { if (!firstParagraph) { lb.Append("\r\n"); } ParagraphLineItem previousItem = null; foreach (ParagraphLine paragraphLine in paragraph.Lines) { foreach (ParagraphLineItem lineItem in paragraphLine.Items) { if (lineItem.ItemType == ItemType.XmlElement || lineItem.ItemType == ItemType.NonReflowableBlock) { if ( //if current line is empty, no matter how big text is, just append it (to // not create extra lines. lb.CurrentLine.Trim().Length > 0 && //Append new line otherwise lb.CurrentLine.Length + lineItem.FirstLine.Length > maxLineLength) { lb.AppendMultilineBlock("\r\n" + paragraph.Offset); } lb.AppendMultilineBlock(lineItem.Text); } //Space between XML elements is not reflown. else if (lineItem.ItemType == ItemType.XmlSpace) { if (previousItem != null && previousItem.IsForcingNewLine) { // do not create new line if it is the last item // in the paragraph if ((lineItem != paragraphLine.Items[paragraphLine.Items.Count - 1]) || (paragraphLine != paragraph.Lines[paragraph.Lines.Count - 1])) { lb.AppendMultilineBlock( "\r\n" + paragraph.Offset); } } else { lb.AppendMultilineBlock(lineItem.Text); } } else if (lineItem.ItemType == ItemType.Text) { string text = lineItem.Text; if (lineItem == paragraphLine.Items[0]) { text = text.TrimStart(); } if (previousItem != null && previousItem.IsForcingNewLine) { lb.AppendMultilineBlock("\r\n" + paragraph.Offset); text = text.TrimStart(); } string[] words = text.Split(' '); for (int i = 0; i < words.Length; i++) { // append the space at the start of the line if (lb.CurrentLine.Length == 0) { lb.AppendMultilineBlock(paragraph.Offset); } string word = words[i]; if (lb.CurrentLine.Length == paragraph.Offset.Length && word.Trim().Length == 0) { continue; } //prepend space if this is not first word in block and not first word on paragraph line //or this is first word in block and block is appended to previous line. bool previousBlockIsText = previousItem != null && previousItem.ItemType == ItemType.Text; string toAppend = (lb.CurrentLine.Length > paragraph.Offset.Length && (i > 0 || previousBlockIsText) ? " " : "") + word; if (lb.CurrentLine.Length + toAppend.Length > maxLineLength) { lb.AppendMultilineBlock("\r\n" + paragraph.Offset); toAppend = word; } lb.AppendMultilineBlock(toAppend); } } previousItem = lineItem; } } firstParagraph = false; } return(lb.ToString()); }