Beispiel #1
0
		public void Rebuild() {
			// keep the first document line
			DocumentLine ls = documentLineTree.GetByNumber(1);
			// but mark all other lines as deleted, and detach them from the other nodes
			for (DocumentLine line = ls.NextLine; line != null; line = line.NextLine) {
				line.isDeleted = true;
				line.parent = line.left = line.right = null;
			}
			// Reset the first line to detach it from the deleted lines
			ls.ResetLine();
			SimpleSegment ds = NewLineFinder.NextNewLine(document, 0);
			List<DocumentLine> lines = new List<DocumentLine>();
			int lastDelimiterEnd = 0;
			while (ds != SimpleSegment.Invalid) {
				ls.TotalLength = ds.Offset + ds.Length - lastDelimiterEnd;
				ls.DelimiterLength = ds.Length;
				lastDelimiterEnd = ds.Offset + ds.Length;
				lines.Add(ls);

				ls = new DocumentLine(document);
				ds = NewLineFinder.NextNewLine(document, lastDelimiterEnd);
			}
			ls.TotalLength = document.TextLength - lastDelimiterEnd;
			lines.Add(ls);
			documentLineTree.RebuildTree(lines);
		}
Beispiel #2
0
		/// <summary>
		/// Sets the total line length and checks the delimiter.
		/// This method can cause line to be deleted when it contains a single '\n' character
		/// and the previous line ends with '\r'.
		/// </summary>
		/// <returns>Usually returns <paramref name="line"/>, but if line was deleted due to
		/// the "\r\n" merge, returns the previous line.</returns>
		DocumentLine SetLineLength(DocumentLine line, int newTotalLength) {
			int delta = newTotalLength - line.TotalLength;
			if (delta != 0) {
				line.TotalLength = newTotalLength;
				DocumentLineTree.UpdateAfterChildrenChange(line);
			}
			// determine new DelimiterLength
			if (newTotalLength == 0) {
				line.DelimiterLength = 0;
			}
			else {
				int lineOffset = line.Offset;
				char lastChar = document.GetCharAt(lineOffset + newTotalLength - 1);
				if (lastChar == '\r' || lastChar == '\u0085' || lastChar == '\u2028' || lastChar == '\u2029') {
					line.DelimiterLength = 1;
				}
				else if (lastChar == '\n') {
					if (newTotalLength >= 2 && document.GetCharAt(lineOffset + newTotalLength - 2) == '\r') {
						line.DelimiterLength = 2;
					}
					else if (newTotalLength == 1 && lineOffset > 0 && document.GetCharAt(lineOffset - 1) == '\r') {
						// we need to join this line with the previous line
						DocumentLine previousLine = line.PreviousLine;
						RemoveLine(line);
						return SetLineLength(previousLine, previousLine.TotalLength + 1);
					}
					else {
						line.DelimiterLength = 1;
					}
				}
				else {
					line.DelimiterLength = 0;
				}
			}
			return line;
		}
Beispiel #3
0
		void RemoveLine(DocumentLine lineToRemove) {
			documentLineTree.RemoveLine(lineToRemove);
		}
Beispiel #4
0
		DocumentLine InsertLineAfter(DocumentLine line, int length) {
			DocumentLine newLine = documentLineTree.InsertLineAfter(line, length);
			return newLine;
		}
Beispiel #5
0
		// optimization note: I tried packing color and isDeleted into a single byte field, but that
		// actually increased the memory requirements. The JIT packs two bools and a byte (delimiterSize)
		// into a single DWORD, but two bytes get each their own DWORD. Three bytes end up in the same DWORD, so
		// apparently the JIT only optimizes for memory when there are at least three small fields.
		// Currently, DocumentLine takes 36 bytes on x86 (8 byte object overhead, 3 pointers, 3 ints, and another DWORD
		// for the small fields).
		// TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint.
		// delimiterSize takes only two bits, the two bools take another two bits; so there's still 
		// 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :)

		/// <summary>
		/// Resets the line to enable its reuse after a document rebuild.
		/// </summary>
		internal void ResetLine() {
			totalLength = delimiterLength = 0;
			isDeleted = color = false;
			left = right = parent = null;
		}
Beispiel #6
0
        // optimization note: I tried packing color and isDeleted into a single byte field, but that
        // actually increased the memory requirements. The JIT packs two bools and a byte (delimiterSize)
        // into a single DWORD, but two bytes get each their own DWORD. Three bytes end up in the same DWORD, so
        // apparently the JIT only optimizes for memory when there are at least three small fields.
        // Currently, DocumentLine takes 36 bytes on x86 (8 byte object overhead, 3 pointers, 3 ints, and another DWORD
        // for the small fields).
        // TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint.
        // delimiterSize takes only two bits, the two bools take another two bits; so there's still
        // 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :)

        /// <summary>
        /// Resets the line to enable its reuse after a document rebuild.
        /// </summary>
        internal void ResetLine()
        {
            totalLength = delimiterLength = 0;
            isDeleted   = color = false;
            left        = right = parent = null;
        }
Beispiel #7
0
        public void Remove(int offset, int length)
        {
            Debug.Assert(length >= 0);
            if (length == 0)
            {
                return;
            }
            DocumentLine startLine       = documentLineTree.GetByOffset(offset);
            int          startLineOffset = startLine.Offset;

            Debug.Assert(offset < startLineOffset + startLine.TotalLength);
            if (offset > startLineOffset + startLine.Length)
            {
                Debug.Assert(startLine.DelimiterLength == 2);
                // we are deleting starting in the middle of a delimiter

                // remove last delimiter part
                SetLineLength(startLine, startLine.TotalLength - 1);
                // remove remaining text
                Remove(offset, length - 1);
                return;
            }

            if (offset + length < startLineOffset + startLine.TotalLength)
            {
                // just removing a part of this line
                SetLineLength(startLine, startLine.TotalLength - length);
                return;
            }
            // merge startLine with another line because startLine's delimiter was deleted
            // possibly remove lines in between if multiple delimiters were deleted
            int charactersRemovedInStartLine = startLineOffset + startLine.TotalLength - offset;

            Debug.Assert(charactersRemovedInStartLine > 0);


            DocumentLine endLine = documentLineTree.GetByOffset(offset + length);

            if (endLine == startLine)
            {
                // special case: we are removing a part of the last line up to the
                // end of the document
                SetLineLength(startLine, startLine.TotalLength - length);
                return;
            }
            int endLineOffset           = endLine.Offset;
            int charactersLeftInEndLine = endLineOffset + endLine.TotalLength - (offset + length);

            // remove all lines between startLine (excl.) and endLine (incl.)
            DocumentLine tmp = startLine.NextLine;
            DocumentLine lineToRemove;

            do
            {
                lineToRemove = tmp;
                tmp          = tmp.NextLine;
                RemoveLine(lineToRemove);
            } while (lineToRemove != endLine);

            SetLineLength(startLine, startLine.TotalLength - charactersRemovedInStartLine + charactersLeftInEndLine);
        }
Beispiel #8
0
        DocumentLine InsertLineAfter(DocumentLine line, int length)
        {
            DocumentLine newLine = documentLineTree.InsertLineAfter(line, length);

            return(newLine);
        }
Beispiel #9
0
 void RemoveLine(DocumentLine lineToRemove) => documentLineTree.RemoveLine(lineToRemove);