// 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); } }