// Update after a removal.
			public static bool RemovalUpdate
						(TextTree tree, TextBuffer buffer,
						 int offset, int length)
					{
						// NOTE: this is here to keep the method calls down to
						//       a minimum... technically, this belongs in the
						//       tree, but it's more efficient to do this here,
						//       where we can access the line/node fields
						//       directly

						// set the default return value
						bool retval = false;

						// declare the start offset of the found lines
						int garbage;

						// get the first line affected by the removal
						TextLine startLine = tree.FindLineByCharOffset
							(offset, out garbage);

						// get the last line affected by the removal
						TextLine endLine = tree.FindLineByCharOffset
							((offset + length + 1), out garbage);

						// handle end of buffer case
						if(endLine == null)
						{
							// get the character count of the buffer
							int bufCount = buffer.CharCount;

							// insert an extra line at the end of the buffer
							buffer.Insert(bufCount, '\n');

							// find the last line of the tree
							endLine = tree.root.LastLine;

							// create the new line node
							TextLine newLine = new TextLine
								(buffer.MarkPosition(bufCount, true),
								 buffer.MarkPosition((bufCount + 1), true));

							// add the new line to the last line's parent
							endLine.parent.InsertChild(endLine, newLine);

							// rebalance the parent
							endLine.parent.Rebalance(tree);

							// set the end line to the new line
							endLine = newLine;

							// flag that an insertion was performed
							retval = true;
						}

						// handle single line case
						if(startLine == endLine)
						{
							// force a character count update for the line
							startLine.UpdateCharCount();

							// invalidate the line
							startLine.Invalidate();

							// we're done
							return retval;
						}

						// merge the content of the two lines into the first
						startLine.end.Move(endLine.EndOffset);

						// get the start line's next sibling
						TextNode first = startLine.next;

						// set the current line to the start's next sibling
						TextLine currLine = (TextLine)first;

						// get the start line's parent
						TextNode startParent = startLine.parent;

						// get the end line's parent
						TextNode endParent = endLine.parent;

						// handle single parent case
						if(startParent == endParent)
						{
							// set the default removal count
							int rmCount = 1;

							// delete the end line's start position
							endLine.start.Delete();

							// delete the end line's end position
							endLine.end.Delete();

							// count and delete the lines to be removed
							while(currLine != endLine)
							{
								// delete the current line's start position
								currLine.start.Delete();

								// delete the current line's end position
								currLine.end.Delete();

								// move to the next line
								currLine = (TextLine)currLine.next;

								// increment the removal count
								++rmCount;
							}

							// remove the deleted lines from their parent
							startParent.RemoveChildren(first, rmCount);

							// rebalance the parent
							startParent.Rebalance(tree);

							// we're done
							return retval;
						}

						// delete the lines to be removed from the start parent
						while(currLine != null)
						{
							// delete the current line's start position
							currLine.start.Delete();

							// delete the current line's end position
							currLine.end.Delete();

							// move to the next line
							currLine = (TextLine)currLine.next;
						}

						// remove the deleted lines from their parent
						if(first != null) { startParent.RemoveChildren(first); }

						// get the current parent
						TextNode currParent = startParent.FindNext();

						// remove lines and groups as needed
						while(currParent != endParent)
						{
							// get the first child of the current parent
							first = currParent.FirstChild;

							// get the current line
							currLine = (TextLine)first;

							// set the default before next line
							TextLine nextLine = null;

							// delete the lines to be removed
							while(currLine != null)
							{
								// delete the current line's start position
								currLine.start.Delete();

								// delete the current line's end position
								currLine.end.Delete();

								// get the before next line
								nextLine = currLine;

								// set the current line to the next
								currLine = (TextLine)currLine.next;
							}

							// find the actual next line
							nextLine = (TextLine)nextLine.FindNext();

							// remove the deleted lines from their parent
							currParent.RemoveChildren(first);

							// remove empty groups up the tree
							while(currParent.ChildCount == 0)
							{
								// get the current parent's parent
								TextNode parent = currParent.parent;

								// remove the current parent
								parent.RemoveChild(currParent);

								// move up the tree
								currParent = parent;
							}

							// set the next parent to the next line's parent
							currParent = nextLine.parent;
						}

						// delete and remove lines from the end parent
						{
							// set the default removal count
							int rmCount = 1;

							// get the first child of the end line's parent
							first = endParent.FirstChild;

							// get the current line
							currLine = (TextLine)first;

							// delete the end line's start position
							endLine.start.Delete();

							// delete the end line's end position
							endLine.end.Delete();

							// count and delete the lines to be removed
							while(currLine != endLine)
							{
								// delete the current line's start position
								currLine.start.Delete();

								// delete the current line's end position
								currLine.end.Delete();

								// move to the next line
								currLine = (TextLine)currLine.next;

								// increment the removal count
								++rmCount;
							}

							// remove the deleted lines from their parent
							endParent.RemoveChildren(first, rmCount);
						}

						// rebalance the end line's parent
						endParent.Rebalance(tree);

						// rebalance the start line's parent
						startLine.parent.Rebalance(tree);

						// return the inserted flag
						return retval;
					}
		// Constructor.
		public TextTree(TextBuffer buffer, TextLayout layout)
				{
					// set the buffer for this text tree
					this.buffer = buffer;

					// set the layout for this text tree
					this.layout = layout;

					// set the root for this text tree
					root = new TextGroup();

					// insert a new line into the buffer
					buffer.Insert(0, '\n');

					// create the first line
					TextLine line = new TextLine
						(buffer.MarkPosition(0, true),
						 buffer.MarkPosition(1, true));

					// insert the first line into the tree
					root.InsertChild(null, line);

					// update the metrics information
					root.UpdateMetrics(layout, true);

					// create the caret position
					caret = buffer.MarkPosition(0, false);

					// create the selection position
					selection = buffer.MarkPosition(0, false);
				}
			// Update after an insertion.
			public static unsafe void InsertionUpdate
						(TextTree tree, TextBuffer buffer,
						 int offset, int length)
					{
						// NOTE: this is here to keep the method calls down to
						//       a minimum... technically, this belongs in the
						//       tree, but it's more efficient to do this here,
						//       where we can access the line/node fields
						//       directly

						// declare the start offset of the insertion line
						int lineStart;

						// find the insertion line
						TextLine line = tree.FindLineByCharOffset
							(offset, out lineStart);

						// get the parent of the insertion line
						TextNode parent = line.Parent;

						// get the end offset of the insertion line
						int lineEnd = line.end.Offset;

						// create a text slice
						TextSlice slice = new TextSlice();

						// get the inserted data into the slice
						buffer.GetSlice(offset, length, slice);

						// get the current line start position
						int currStart = lineStart;

						// get the current line end position
						int currEnd = (offset + 1);

						// set the default new line list
						TextLine first = null;

						// set the default previous new line
						TextLine prev = null;

						// find and create new lines, quickly
						fixed(char* start = &slice.chars[slice.start])
						{
							char* curr = start;
							// get the insertion end position
							char* end = (curr + slice.length);

							// find and create new lines
							while(curr != end)
							{
								if(*curr == '\n')
								{
									if(currStart == lineStart)
									{
										// shorten the insertion line
										line.end.Move(currEnd);
									}
									else
									{
										// create a new line
										TextLine newline = new TextLine
											(buffer.MarkPosition(currStart, true),
											 buffer.MarkPosition(currEnd, true));

										// update list links
										if(first == null)
										{
											// set the current line as the first
											first = newline;
										}
										else
										{
											// set the current line's prev
											newline.prev = prev;

											// set the previous line's next
											prev.next = newline;
										}

										// set the previous line to the current
										prev = newline;
									}

									// update the current line start position
									currStart = currEnd;
								}

								// increment the current input pointer
								++curr;

								// increment the current line end position
								++currEnd;
							}
						}

						// insert new lines and rebalance parent, if needed
						if(first != null)
						{
							// add any remaining characters to new line
							if(currEnd < lineEnd)
							{
								// create a new line
								TextLine newline = new TextLine
									(buffer.MarkPosition(currStart, true),
									 buffer.MarkPosition(currEnd, true));

								// set the current line's prev reference
								newline.prev = prev;

								// set the previous line's next reference
								prev.next = newline;
							}

							// insert the new lines
							parent.InsertChildren(line, first);

							// rebalance, starting at the new lines' parent
							parent.Rebalance(tree);
						}
					}