Exemple #1
0
 internal HeightTreeNode(DocumentLine documentLine, double height)
 {
     this.documentLine = documentLine;
     this.totalCount = 1;
     this.lineNode = new HeightTreeLineNode(height);
     this.totalHeight = height;
 }
Exemple #2
0
 void ILineTracker.BeforeRemoveLine(DocumentLine line)
 {
     ILineTracker targetTracker = targetObject.Target as ILineTracker;
     if (targetTracker != null)
         targetTracker.BeforeRemoveLine(line);
     else
         Deregister();
 }
Exemple #3
0
 void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine)
 {
     ILineTracker targetTracker = targetObject.Target as ILineTracker;
     if (targetTracker != null)
         targetTracker.LineInserted(insertionPos, newLine);
     else
         Deregister();
 }
Exemple #4
0
        public VisualLine(TextLayer parent, DocumentLine documentLine)
            : base(parent)
        {
            DocumentLine = documentLine;
            elements = new List<VisualLineElement>();

            Init();

            documentLine.TextChanged += OnTextChanged;
        }
 internal CollapsedLineSection(HeightTree heightTree, DocumentLine start, DocumentLine end)
 {
     this.heightTree = heightTree;
     this.start = start;
     this.end = end;
     #if DEBUG
     unchecked {
         this.ID = " #" + (nextId++);
     }
     #endif
 }
Exemple #6
0
 public double GetHeight(DocumentLine line)
 {
     return GetNode(line).lineNode.height;
 }
Exemple #7
0
 void CheckIsInSection(CollapsedLineSection cs, DocumentLine line)
 {
     HeightTreeNode node = GetNode(line);
     if (node.lineNode.collapsedSections != null && node.lineNode.collapsedSections.Contains(cs))
         return;
     while (node != null) {
         if (node.collapsedSections != null && node.collapsedSections.Contains(cs))
             return;
         node = node.parent;
     }
     throw new InvalidOperationException(cs + " not found for line " + line);
 }
Exemple #8
0
 void HighlightLineAndUpdateTreeList(DocumentLine line, int lineNumber)
 {
     //Debug.WriteLine("Highlight line " + lineNumber + (highlightedLine != null ? "" : " (span stack only)"));
     spanStack = storedSpanStacks[lineNumber - 1];
     HighlightLineInternal(line);
     if (!EqualSpanStacks(spanStack, storedSpanStacks[lineNumber])) {
         isValid[lineNumber] = true;
         //Debug.WriteLine("Span stack in line " + lineNumber + " changed from " + storedSpanStacks[lineNumber] + " to " + spanStack);
         storedSpanStacks[lineNumber] = spanStack;
         if (lineNumber + 1 < isValid.Count) {
             isValid[lineNumber + 1] = false;
             firstInvalidLine = lineNumber + 1;
         } else {
             firstInvalidLine = int.MaxValue;
         }
         OnHighlightStateChanged(line, lineNumber);
     } else if (firstInvalidLine == lineNumber) {
         isValid[lineNumber] = true;
         firstInvalidLine = isValid.IndexOf(false);
         if (firstInvalidLine < 0)
             firstInvalidLine = int.MaxValue;
     }
 }
Exemple #9
0
 HeightTreeNode GetNode(DocumentLine ls)
 {
     return GetNodeByIndex(ls.LineNumber - 1);
 }
Exemple #10
0
 HeightTreeNode InsertAfter(HeightTreeNode node, DocumentLine newLine)
 {
     HeightTreeNode newNode = new HeightTreeNode(newLine, defaultLineHeight);
     if (node.right == null) {
         if (node.lineNode.collapsedSections != null) {
             // we are inserting directly after node - so copy all collapsedSections
             // that do not end at node.
             foreach (CollapsedLineSection cs in node.lineNode.collapsedSections) {
                 if (cs.End != node.documentLine)
                     newNode.AddDirectlyCollapsed(cs);
             }
         }
         InsertAsRight(node, newNode);
     } else {
         node = node.right.LeftMost;
         if (node.lineNode.collapsedSections != null) {
             // we are inserting directly before node - so copy all collapsedSections
             // that do not start at node.
             foreach (CollapsedLineSection cs in node.lineNode.collapsedSections) {
                 if (cs.Start != node.documentLine)
                     newNode.AddDirectlyCollapsed(cs);
             }
         }
         InsertAsLeft(node, newNode);
     }
     return newNode;
 }
Exemple #11
0
 public void LineInserted(DocumentLine insertionPos, DocumentLine newDocLine)
 {
     var prevLine = lines[insertionPos];
     var line = new VisualLine(this, newDocLine);
     line.BringNextToControl(prevLine,true);
     lines.Add(newDocLine,line);
 }
Exemple #12
0
        void HighlightLineInternal(DocumentLine line)
        {
            lineStartOffset = line.Offset;
            lineText = document.GetText(line.Offset, line.Length);
            position = 0;
            ResetColorStack();
            HighlightingRuleSet currentRuleSet = this.CurrentRuleSet;
            Stack<Match[]> storedMatchArrays = new Stack<Match[]>();
            Match[] matches = AllocateMatchArray(currentRuleSet.Spans.Count);
            Match endSpanMatch = null;

            while (true) {
                for (int i = 0; i < matches.Length; i++) {
                    if (matches[i] == null || (matches[i].Success && matches[i].Index < position))
                        matches[i] = currentRuleSet.Spans[i].StartExpression.Match(lineText, position);
                }
                if (endSpanMatch == null && !spanStack.IsEmpty)
                    endSpanMatch = spanStack.Peek().EndExpression.Match(lineText, position);

                Match firstMatch = Minimum(matches, endSpanMatch);
                if (firstMatch == null)
                    break;

                HighlightNonSpans(firstMatch.Index);

                Debug.Assert(position == firstMatch.Index);

                if (firstMatch == endSpanMatch) {
                    HighlightingSpan poppedSpan = spanStack.Peek();
                    if (!poppedSpan.SpanColorIncludesEnd)
                        PopColor(); // pop SpanColor
                    PushColor(poppedSpan.EndColor);
                    position = firstMatch.Index + firstMatch.Length;
                    PopColor(); // pop EndColor
                    if (poppedSpan.SpanColorIncludesEnd)
                        PopColor(); // pop SpanColor
                    spanStack = spanStack.Pop();
                    currentRuleSet = this.CurrentRuleSet;
                    //FreeMatchArray(matches);
                    if (storedMatchArrays.Count > 0) {
                        matches = storedMatchArrays.Pop();
                        int index = currentRuleSet.Spans.IndexOf(poppedSpan);
                        Debug.Assert(index >= 0 && index < matches.Length);
                        if (matches[index].Index == position) {
                            throw new InvalidOperationException(
                                "A highlighting span matched 0 characters, which would cause an endless loop.\n" +
                                "Change the highlighting definition so that either the start or the end regex matches at least one character.\n" +
                                "Start regex: " + poppedSpan.StartExpression + "\n" +
                                "End regex: " + poppedSpan.EndExpression);
                        }
                    } else {
                        matches = AllocateMatchArray(currentRuleSet.Spans.Count);
                    }
                } else {
                    int index = Array.IndexOf(matches, firstMatch);
                    Debug.Assert(index >= 0);
                    HighlightingSpan newSpan = currentRuleSet.Spans[index];
                    spanStack = spanStack.Push(newSpan);
                    currentRuleSet = this.CurrentRuleSet;
                    storedMatchArrays.Push(matches);
                    matches = AllocateMatchArray(currentRuleSet.Spans.Count);
                    if (newSpan.SpanColorIncludesStart)
                        PushColor(newSpan.SpanColor);
                    PushColor(newSpan.StartColor);
                    position = firstMatch.Index + firstMatch.Length;
                    PopColor();
                    if (!newSpan.SpanColorIncludesStart)
                        PushColor(newSpan.SpanColor);
                }
                endSpanMatch = null;
            }
            HighlightNonSpans(line.Length);

            PopAllColors();
        }
Exemple #13
0
 public static ISegment GetTrailingWhitespace(TextDocument document, DocumentLine documentLine)
 {
     if (documentLine == null)
         throw new ArgumentNullException("documentLine");
     ISegment segment = GetWhitespaceBefore(document, documentLine.EndOffset);
     // If the whole line consists of whitespace, we consider all of it as leading whitespace,
     // so return an empty segment as trailing whitespace.
     if (segment.Offset == documentLine.Offset)
         return new SimpleSegment(documentLine.EndOffset, 0);
     else
         return segment;
 }
            protected override void OnHighlightStateChanged(DocumentLine line, int lineNumber)
            {
                base.OnHighlightStateChanged(line, lineNumber);
                if (colorizer.lineNumberBeingColorized != lineNumber) {
                    // Ignore notifications for any line except the one we're interested in.
                    // This improves the performance as Redraw() can take quite some time when called repeatedly
                    // while scanning the document (above the visible area) for highlighting changes.
                    return;
                }
                if (textLayer.Document != this.Document) {
                    // May happen if document on text view was changed but some user code is still using the
                    // existing IHighlighter instance.
                    return;
                }

                // The user may have inserted "/*" into the current line, and so far only that line got redrawn.
                // So when the highlighting state is changed, we issue a redraw for the line immediately below.
                // If the highlighting state change applies to the lines below, too, the construction of each line
                // will invalidate the next line, and the construction pass will regenerate all lines.

                Debug.WriteLine("OnHighlightStateChanged forces redraw of line " + (lineNumber + 1));

                // If the VisualLine construction is in progress, we have to avoid sending redraw commands for
                // anything above the line currently being constructed.
                // It takes some explanation to see why this cannot happen.
                // VisualLines always get constructed from top to bottom.
                // Each VisualLine construction calls into the highlighter and thus forces an update of the
                // highlighting state for all lines up to the one being constructed.

                // To guarantee that we don't redraw lines we just constructed, we need to show that when
                // a VisualLine is being reused, the highlighting state at that location is still up-to-date.

                // This isn't exactly trivial and the initial implementation was incorrect in the presence of external document changes
                // (e.g. split view).

                // For the first line in the view, the TextLayer.VisualLineConstructionStarting event is used to check that the
                // highlighting state is up-to-date. If it isn't, this method will be executed, and it'll mark the first line
                // in the view as requiring a redraw. This is safely possible because that event occurs before any lines are reused.

                // Once we take care of the first visual line, we won't get in trouble with other lines due to the top-to-bottom
                // construction process.

                // We'll prove that: if line N is being reused, then the highlighting state is up-to-date until (end of) line N-1.

                // Start of induction: the first line in view is reused only if the highlighting state was up-to-date
                // until line N-1 (no change detected in VisualLineConstructionStarting event).

                // Induction step:
                // If another line N+1 is being reused, then either
                //     a) the previous line (the visual line containing document line N) was newly constructed
                // or  b) the previous line was reused
                // In case a, the construction updated the highlighting state. This means the stack at end of line N is up-to-date.
                // In case b, the highlighting state at N-1 was up-to-date, and the text of line N was not changed.
                //   (if the text was changed, the line could not have been reused).
                // From this follows that the highlighting state at N is still up-to-date.

                // The above proof holds even in the presence of folding: folding only ever hides text in the middle of a visual line.
                // Our Colorize-override ensures that the highlighting state is always updated for the LastDocumentLine,
                // so it will always invalidate the next visual line when a folded line is constructed
                // and the highlighting stack has changed.

                throw new NotImplementedException();
                //textLayer.Redraw(line.NextLine, DispatcherPriority.Normal);

                /*
                 * Meta-comment: "why does this have to be so complicated?"
                 *
                 * The problem is that I want to re-highlight only on-demand and incrementally;
                 * and at the same time only repaint changed lines.
                 * So the highlighter and the VisualLine construction both have to run in a single pass.
                 * The highlighter must take care that it never touches already constructed visual lines;
                 * if it detects that something must be redrawn because the highlighting state changed,
                 * it must do so early enough in the construction process.
                 * But doing it too early means it doesn't have the information necessary to re-highlight and redraw only the desired parts.
                 */
            }
Exemple #15
0
 void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength)
 {
     ILineTracker targetTracker = targetObject.Target as ILineTracker;
     if (targetTracker != null)
         targetTracker.SetLineLength(line, newTotalLength);
     else
         Deregister();
 }
Exemple #16
0
        /// <summary>
        /// Gets the location from an offset.
        /// </summary>
        /// <seealso cref="GetOffset(TextLocation)"/>
        public TextLocation GetLocation(int offset)
        {
            DocumentLine line = GetLineByOffset(offset);

            return(new TextLocation(line.LineNumber, offset - line.Offset + 1));
        }
Exemple #17
0
 /// <summary>
 /// Collapses the specified text section.
 /// Runtime: O(log n)
 /// </summary>
 public CollapsedLineSection CollapseText(DocumentLine start, DocumentLine end)
 {
     if (!document.Lines.Contains(start))
         throw new ArgumentException("Line is not part of this document", "start");
     if (!document.Lines.Contains(end))
         throw new ArgumentException("Line is not part of this document", "end");
     int length = end.LineNumber - start.LineNumber + 1;
     if (length < 0)
         throw new ArgumentException("start must be a line before end");
     CollapsedLineSection section = new CollapsedLineSection(this, start, end);
     AddCollapsedSection(section, length);
     #if DEBUG
     CheckProperties();
     #endif
     return section;
 }
Exemple #18
0
        public void Rebuild()
        {
            // keep the first document line
            DocumentLine ls = documentLineTree.GetByNumber(1);
            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.ResetLine();
            ls.TotalLength = document.TextLength - lastDelimiterEnd;
            lines.Add(ls);
            documentLineTree.RebuildTree(lines);
            foreach (ILineTracker lineTracker in lineTrackers)
                lineTracker.RebuildDocument();
        }
Exemple #19
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)
 {
     //			changedLines.Add(line);
     //			deletedOrChangedLines.Add(line);
     int delta = newTotalLength - line.TotalLength;
     if (delta != 0) {
         foreach (ILineTracker lt in lineTrackers)
             lt.SetLineLength(line, newTotalLength);
         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') {
             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;
         }
     }
     line.RaiseTextChanged();
     return line;
 }
Exemple #20
0
 void RemoveLine(DocumentLine lineToRemove)
 {
     foreach (ILineTracker lt in lineTrackers)
         lt.BeforeRemoveLine(lineToRemove);
     documentLineTree.RemoveLine(lineToRemove);
     //			foreach (ILineTracker lt in lineTracker)
     //				lt.AfterRemoveLine(lineToRemove);
     //			deletedLines.Add(lineToRemove);
     //			deletedOrChangedLines.Add(lineToRemove);
 }
Exemple #21
0
 DocumentLine InsertLineAfter(DocumentLine line, int length)
 {
     DocumentLine newLine = documentLineTree.InsertLineAfter(line, length);
     foreach (ILineTracker lt in lineTrackers)
         lt.LineInserted(line, newLine);
     return newLine;
 }
 /// <summary>
 /// Creates a new VisualLineConstructionStartEventArgs instance.
 /// </summary>
 public VisualLineConstructionStartEventArgs(DocumentLine firstLineInView)
 {
     if (firstLineInView == null)
         throw new ArgumentNullException("firstLineInView");
     this.FirstLineInView = firstLineInView;
 }
Exemple #23
0
 public double GetVisualPosition(DocumentLine line)
 {
     return GetVisualPositionFromNode(GetNode(line));
 }
Exemple #24
0
 public static ISegment GetLeadingWhitespace(TextDocument document, DocumentLine documentLine)
 {
     if (documentLine == null)
         throw new ArgumentNullException("documentLine");
     return GetWhitespaceAfter(document, documentLine.Offset);
 }
Exemple #25
0
 void ILineTracker.BeforeRemoveLine(DocumentLine line)
 {
     HeightTreeNode node = GetNode(line);
     if (node.lineNode.collapsedSections != null) {
         foreach (CollapsedLineSection cs in node.lineNode.collapsedSections.ToArray()) {
             if (cs.Start == line && cs.End == line) {
                 cs.Start = null;
                 cs.End = null;
             } else if (cs.Start == line) {
                 Uncollapse(cs);
                 cs.Start = line.NextLine;
                 AddCollapsedSection(cs, cs.End.LineNumber - cs.Start.LineNumber + 1);
             } else if (cs.End == line) {
                 Uncollapse(cs);
                 cs.End = line.PreviousLine;
                 AddCollapsedSection(cs, cs.End.LineNumber - cs.Start.LineNumber + 1);
             }
         }
     }
     BeginRemoval();
     RemoveNode(node);
     // clear collapsedSections from removed line: prevent damage if removed line is in "nodesToCheckForMerging"
     node.lineNode.collapsedSections = null;
     EndRemoval();
 }
Exemple #26
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;
 }
Exemple #27
0
 //        void ILineTracker.AfterRemoveLine(DocumentLine line)
 //        {
 //
 //        }
 void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine)
 {
     InsertAfter(GetNode(insertionPos), newLine);
     #if DEBUG
     CheckProperties();
     #endif
 }
Exemple #28
0
 public void BeforeRemoveLine(DocumentLine documentLine)
 {
     var line = lines[documentLine];
     RemoveChild(line,true);
     lines.Remove(documentLine);
 }
Exemple #29
0
 void ILineTracker.SetLineLength(DocumentLine ls, int newTotalLength)
 {
 }
Exemple #30
0
 public void SetLineLength(DocumentLine line, int newTotalLength)
 {
 }
Exemple #31
0
 public void SetHeight(DocumentLine line, double val)
 {
     var node = GetNode(line);
     node.lineNode.height = val;
     UpdateAfterChildrenChange(node);
 }