]> O.S.I.I.S - jp/crowedit.git/commitdiff
editors Y scrolling and folding optimizations
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Feb 2025 11:01:40 +0000 (12:01 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Feb 2025 11:01:40 +0000 (12:01 +0100)
CrowEditBase/src/Compiler/SourceDocument.cs
CrowEditBase/src/Compiler/SyntaxNode.cs
CrowEditBase/src/Editor.cs
CrowEditBase/src/SourceEditor.cs
CrowEditBase/src/TextBuffer.cs
CrowEditBase/src/TextDocument.cs
CrowEditBase/ui/CrowEdit.style

index d0b2ec4e614f08e1cc6b547073f694c3a3d56a51..24f9068a2036f0e9d9b4a3d99a6cf95af062cf49 100644 (file)
@@ -36,14 +36,14 @@ namespace CrowEditBase
                        if (!IsParsed || pos == 0 || Tokens.Length == 0)
                                return default;
                        int idx = Tokens.BinarySearch(new  Token () {Start = pos});
-                       return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx - 1;
+                       return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx;
                }
 
                
                /// <summary>
                /// if outermost is true, return oldest ancestor exept root node, useful for folding.
                /// </summary>
-               /*public SyntaxNode FindNodeIncludingPosition (int pos, bool outerMost = false) {
+               public SyntaxNode FindNodeIncludingPosition (int pos, bool outerMost = false) {
                        if (root == null)
                                return null;
                        if (!root.Contains (pos))
@@ -55,7 +55,7 @@ namespace CrowEditBase
                        }
                        return sn;
                }
-               public T FindNodeIncludingPosition<T> (int pos) {
+               /*public T FindNodeIncludingPosition<T> (int pos) {
                        if (root == null)
                                return default;
                        if (!root.Contains (pos))
index c9819731c691c9246e6a22760b77f103bc488147..07d53638856d53f59d06e7ed31579a8fc4f00cbf 100644 (file)
@@ -37,7 +37,7 @@ namespace CrowEditBase
                public int StartLine { get; private set; }
                public virtual int LineCount => lineCount;
                public virtual bool IsComplete => TokenCount.HasValue;
-               public virtual bool IsFoldable => IsComplete && Parent.StartLine != StartLine && lineCount > 1;
+               public virtual bool IsFoldable => IsComplete && !(Parent != Root && Parent.StartLine == StartLine) && lineCount > 1;
                public virtual SyntaxRootNode Root => Parent.Root;
                public virtual void UnfoldToTheTop () {
                        isFolded = false;
@@ -83,13 +83,16 @@ namespace CrowEditBase
                }
                public virtual SyntaxNode NextSiblingOrParentsNextSibling
                        => NextSibling ?? Parent.NextSiblingOrParentsNextSibling;
-               public IEnumerable<SyntaxNode> FoldableNodes {
+               public IEnumerable<SyntaxNode> VisibleFoldableNodes {
                        get {
-                               if (IsFoldable)
+                               if (IsFoldable) {
                                        yield return this;
-                               foreach (SyntaxNode n in Children) {
-                                       foreach (SyntaxNode folds in n.FoldableNodes)
-                                               yield return folds;
+                               }
+                               if (!isFolded) {
+                                       foreach (SyntaxNode n in Children) {
+                                               foreach (SyntaxNode folds in n.VisibleFoldableNodes)
+                                                       yield return folds;
+                                       }
                                }
                        }
                }
@@ -211,5 +214,10 @@ namespace CrowEditBase
                }
                public bool IsSimilar (SyntaxNode other) => this.GetType() == other?.GetType();
 
-       }
+
+        public class CompareOnStartLine : IComparer<SyntaxNode>
+        {
+            public int Compare(SyntaxNode x, SyntaxNode y) => x.StartLine - y.StartLine;
+        }
+    }
 }
\ No newline at end of file
index d3b738137f8ddfae9e1b0ac18c111a76c25e5600..4767d0a225ebff6a082a58c0dccb106ffcbfa98a 100644 (file)
@@ -308,7 +308,7 @@ namespace Crow
                /// <summary>
                /// on screen visible line bounded by the client rectangle
                /// </summary>
-               protected int visibleLines => (int)((double)ClientRectangle.Height / lineHeight);
+               protected int visibleLines => (int)Math.Ceiling(ClientRectangle.Height / lineHeight);
                /// <summary>
                /// total line count
                /// </summary>
@@ -333,6 +333,7 @@ namespace Crow
                                                else {
                                                        gr.TextExtents (document.GetText (l), App.TabulationSize, out tmp);
                                                        l.LengthInPixel = (int)Math.Ceiling (tmp.XAdvance);
+                                                       document.SetLine(i, l);
                                                }
                                        }
                                        if (l.LengthInPixel > document.GetLine (longestLine).LengthInPixel)
@@ -347,9 +348,7 @@ namespace Crow
                                document.ExitReadLock ();
                        }
                }
-               protected virtual void drawContent (IContext gr) {
-                       gr.Translate (-ScrollX, -ScrollY);
-
+               protected virtual void drawContent (IContext gr) {                      
                        Rectangle cb = ClientRectangle;
                        fe = gr.FontExtents;
                        double lineHeight = fe.Ascent + fe.Descent;
@@ -357,6 +356,8 @@ namespace Crow
                        CharLocation selStart = default, selEnd = default;
                        bool selectionNotEmpty = false;
 
+                       gr.Translate (-ScrollX, 0);
+
                        document.EnterReadLock();
                        
                        try {
@@ -388,91 +389,97 @@ namespace Crow
                                //}
 
                                if (document.Length > 0) {
+                                       int skippedLines = (int)Math.Floor(ScrollY / lineHeight);
+                                       int curLine = skippedLines;
+                                       double y = -(ScrollY % lineHeight);
+
                                        Foreground?.SetAsSource (IFace, gr);
 
                                        TextExtents extents;
                                        Span<byte> bytes = stackalloc byte[128];
-                                       double y = 0;
-
-                                       for (int i = 0; i < document.LinesCount; i++) {
-                                               if (!cancelLinePrint (lineHeight, y, cb.Height)) {
-                                                       int encodedBytes = -1;
-                                                       TextLine l = document.GetLine (i);
-                                                       if (l.Length > 0) {
-                                                               int size = l.Length * 4 + 1;
-                                                               if (bytes.Length < size)
-                                                                       bytes = new byte[size];
-
-                                                               encodedBytes = document.GetText (l).ToUtf8 (bytes);
-                                                               bytes[encodedBytes++] = 0;
-
-                                                               if (l.LengthInPixel < 0) {
-                                                                       gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
-                                                                       l.LengthInPixel = (int)extents.XAdvance;
-                                                               }
+                                       
+                                       while (curLine < document.LinesCount && curLine - skippedLines < visibleLines) {
+                                               
+                                               int encodedBytes = -1;
+                                               TextLine l = document.GetLine (curLine);
+                                               if (l.Length > 0) {
+                                                       int size = l.Length * 4 + 1;
+                                                       if (bytes.Length < size)
+                                                               bytes = new byte[size];
+
+                                                       encodedBytes = document.GetText (l).ToUtf8 (bytes);
+                                                       bytes[encodedBytes++] = 0;
+
+                                                       if (l.LengthInPixel < 0) {
+                                                               gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+                                                               l.LengthInPixel = (int)extents.XAdvance;
+                                                               document.SetLine(curLine, l);
                                                        }
+                                               }
 
-                                                       RectangleD lineRect = new RectangleD (
-                                                               (int)cb.X,
-                                                               y + cb.Top, l.LengthInPixel, lineHeight);
+                                               RectangleD lineRect = new RectangleD (
+                                                       (int)cb.X,
+                                                       y + cb.Top, l.LengthInPixel, lineHeight);
 
-                                                       if (encodedBytes > 0) {
+                                               if (encodedBytes > 0) {
+                                                       gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+                                                       gr.ShowText (bytes.Slice (0, encodedBytes));
+                                               }
+                                               /********** DEBUG TextLineCollection *************
+                                               gr.SetSource (Colors.Red);
+                                               gr.SetFontSize (9);
+                                               gr.MoveTo (700, lineRect.Y + fe.Ascent);
+                                               gr.ShowText ($"({lines[i].Start}, {lines[i].End}, {lines[i].EndIncludingLineBreak})");
+                                               gr.SetFontSize (Font.Size);
+                                               Foreground.SetAsSource (IFace, gr);
+                                               ********** DEBUG TextLineCollection *************/
+
+                                               if (selectionNotEmpty) {
+                                                       RectangleD selRect = lineRect;
+
+                                                       if (curLine >= selStart.Line && curLine <= selEnd.Line) {
+                                                               if (selStart.Line == selEnd.Line) {
+                                                                       selRect.X = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
+                                                               } else if (curLine == selStart.Line) {
+                                                                       double newX = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width -= (newX - selRect.X) - 10.0;
+                                                                       selRect.X = newX;
+                                                               } else if (curLine == selEnd.Line) {
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
+                                                               } else
+                                                                       selRect.Width += 10.0;
+                                                       } else {
+                                                               y += lineHeight;
+                                                               curLine++;
+                                                               continue;
+                                                       }
+
+                                                       gr.SetSource (selBackground);
+                                                       gr.Rectangle (selRect);
+                                                       if (encodedBytes < 0)
+                                                               gr.Fill ();
+                                                       else {
+                                                               gr.FillPreserve ();
+                                                               gr.Save ();
+                                                               gr.Clip ();
+                                                               gr.SetSource (SelectionForeground);
                                                                gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
                                                                gr.ShowText (bytes.Slice (0, encodedBytes));
+                                                               gr.Restore ();
                                                        }
-                                                       /********** DEBUG TextLineCollection *************
-                                                       gr.SetSource (Colors.Red);
-                                                       gr.SetFontSize (9);
-                                                       gr.MoveTo (700, lineRect.Y + fe.Ascent);
-                                                       gr.ShowText ($"({lines[i].Start}, {lines[i].End}, {lines[i].EndIncludingLineBreak})");
-                                                       gr.SetFontSize (Font.Size);
                                                        Foreground.SetAsSource (IFace, gr);
-                                                       ********** DEBUG TextLineCollection *************/
-
-                                                       if (selectionNotEmpty) {
-                                                               RectangleD selRect = lineRect;
-
-                                                               if (i >= selStart.Line && i <= selEnd.Line) {
-                                                                       if (selStart.Line == selEnd.Line) {
-                                                                               selRect.X = selStart.VisualCharXPosition + cb.X;
-                                                                               selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
-                                                                       } else if (i == selStart.Line) {
-                                                                               double newX = selStart.VisualCharXPosition + cb.X;
-                                                                               selRect.Width -= (newX - selRect.X) - 10.0;
-                                                                               selRect.X = newX;
-                                                                       } else if (i == selEnd.Line) {
-                                                                               selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
-                                                                       } else
-                                                                               selRect.Width += 10.0;
-                                                               } else {
-                                                                       y += lineHeight;
-                                                                       continue;
-                                                               }
-
-                                                               gr.SetSource (selBackground);
-                                                               gr.Rectangle (selRect);
-                                                               if (encodedBytes < 0)
-                                                                       gr.Fill ();
-                                                               else {
-                                                                       gr.FillPreserve ();
-                                                                       gr.Save ();
-                                                                       gr.Clip ();
-                                                                       gr.SetSource (SelectionForeground);
-                                                                       gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
-                                                                       gr.ShowText (bytes.Slice (0, encodedBytes));
-                                                                       gr.Restore ();
-                                                               }
-                                                               Foreground.SetAsSource (IFace, gr);
-                                                       }
                                                }
+                                       
                                                y += lineHeight;
+                                               curLine++;
                                        }
                                }
                        } finally {
                                document.ExitReadLock ();
                        }
 
-                       gr.Translate (ScrollX, ScrollY);
+                       gr.Translate (ScrollX, 0);
                }
                protected int getLineIndexFromMousePosition (Point mouseLocalPos) =>
                        (int)Math.Min (Math.Max (0, Math.Floor ((mouseLocalPos.Y + ScrollY)/ lineHeight)), visualLineCount - 1);
@@ -490,7 +497,6 @@ namespace Crow
                        updateLocation (ref newLoc);
                        hoverLoc = newLoc;
                }
-               protected virtual bool cancelLinePrint (double lineHeght, double y, int clientHeight) => false;
                RectangleD? textCursor = null;
 
                public virtual bool DrawCursor (IContext ctx, out Rectangle rect) {
index 9e87ebd3384a4c2afc6feb0c79901b1a24302a7b..ce947960698bb82d5f9fad8dbc16557395a444cf 100644 (file)
@@ -11,6 +11,7 @@ using CrowEditBase;
 using static CrowEditBase.CrowEditBase;
 using System.Collections.Generic;
 using System.Linq;
+using System.Collections.Frozen;
 
 namespace Crow
 {
@@ -225,6 +226,7 @@ namespace Crow
                        if (mouseIsInMargin) {
                                Rectangle rFold = new Rectangle (leftMargin - foldMargin - leftMarginRightGap,
                                        (int)(lineHeight * getVisualLine(hoverLoc.Value.Line) + lineHeight / 2.0 - foldSize / 2.0) - ScrollY, foldSize, foldSize);
+                               rFold.Inflate(2);
                                mouseIsInFoldRect = rFold.ContainsOrIsEqual (mLoc);
                                RegisterForRedraw();
                                return;
@@ -357,7 +359,7 @@ namespace Crow
                SyntaxNode getFoldStartingAt (int line) {
                        if (!(Document is SourceDocument doc))
                                return null;
-                       IEnumerable<SyntaxNode> folds = doc.Root.FoldableNodes;
+                       IEnumerable<SyntaxNode> folds = doc.Root.VisibleFoldableNodes;
                        if (folds == null)
                                return null;
                        return folds.FirstOrDefault (n => n.StartLine == line);
@@ -367,7 +369,7 @@ namespace Crow
                                return null;
                        doc.EnterReadLock();
                        try {
-                               IEnumerable<SyntaxNode> folds = doc.Root.FoldableNodes;
+                               IEnumerable<SyntaxNode> folds = doc.Root.VisibleFoldableNodes;
                                if (folds == null)
                                        return null;
                                return folds.LastOrDefault (n => n.StartLine <= line && n.EndLine >= line);
@@ -382,7 +384,7 @@ namespace Crow
                        doc.EnterReadLock();
                        try {
                                int foldedLines = 0;
-                               IEnumerator<SyntaxNode> foldsEnum = doc.Root.FoldableNodes.GetEnumerator();
+                               IEnumerator<SyntaxNode> foldsEnum = doc.Root.VisibleFoldableNodes.GetEnumerator();
                                bool notEndOfFolds = foldsEnum.MoveNext();
                                while (notEndOfFolds && foldsEnum.Current.StartLine < absoluteLine) {
                                        if (foldsEnum.Current.isFolded) {
@@ -407,7 +409,7 @@ namespace Crow
                        doc.EnterReadLock();
                        try {
                                int foldedLines = 0;
-                               IEnumerator<SyntaxNode> nodeEnum = doc.Root.FoldableNodes.GetEnumerator ();
+                               IEnumerator<SyntaxNode> nodeEnum = doc.Root.VisibleFoldableNodes.GetEnumerator ();
                                if (!nodeEnum.MoveNext())
                                        return 0;
 
@@ -499,7 +501,7 @@ namespace Crow
 
                }
                protected override void drawContent (IContext gr) {
-                       if (!(Document is SourceDocument doc && doc.Root != null)) {
+                       if (!(Document is SourceDocument doc)) {
                                base.drawContent (gr);
                                return;
                        }
@@ -513,21 +515,23 @@ namespace Crow
                                Color marginBG = App.MarginBackground;
                                Color marginFG = Colors.Ivory;
                                Rectangle cb = ClientRectangle;
-                               RectangleD marginRect = new RectangleD (cb.X + ScrollX, cb.Y, leftMargin - leftMarginRightGap, cb.Height);
+                               RectangleD marginRect = new RectangleD (cb.X, cb.Y, leftMargin - leftMarginRightGap, cb.Height);
 
                                gr.SetSource (marginBG);
                                gr.Rectangle (marginRect);
                                gr.Fill();
-
                                
                                if (!doc.IsParsed) {
                                        base.drawContent (gr);
                                        return;
                                }
 
+                               gr.Translate (-ScrollX, 0);
+
                                double lineNumWidth = gr.TextExtents (Document.LinesCount.ToString()).Width;
 
                                marginRect.Height = lineHeight;
+                               marginRect.Left += ScrollX;
                                cb.Left += leftMargin;
 
                                CharLocation selStart = default, selEnd = default;
@@ -599,51 +603,46 @@ namespace Crow
 
 
                                //double spacePixelWidth = gr.TextExtents (" ").XAdvance;
-                               int x = 0;
                                double  pixX = cb.Left,
                                                pixY = cb.Top;
 
                                Foreground.SetAsSource (IFace, gr);
-                               gr.Translate (-ScrollX, -ScrollY);
 
                                ReadOnlySpan<char> sourceBytes = doc.source;
                                Span<byte> bytes = stackalloc byte[128];
                                TextExtents extents;
-                               int tokPtr = 0;
-                               Token tok = doc.Tokens[tokPtr];
+                               
+                               
 
                                ReadOnlySpan<char> buff = sourceBytes;
 
-                               SyntaxNode curNode = null;
+                               
+                               int printedLines = 0;
+                               int curLine = (int)Math.Floor(ScrollY / lineHeight);
+                               pixY = -(ScrollY % lineHeight);
 
-                               IEnumerator<SyntaxNode> nodeEnum = doc.Root.FoldableNodes.GetEnumerator ();
-                               bool notEndOfNodes = nodeEnum.MoveNext();
+                               
+                               IEnumerator<SyntaxNode> foldsEnum = doc.Root.VisibleFoldableNodes.GetEnumerator ();
+                               bool notEndOfFolds = foldsEnum.MoveNext();
 
-                               gr.LineWidth = 1;
-                               int l = 0;
-                               while (l < Document.LinesCount) {
-                                       //if (!cancelLinePrint (lineHeight, lineHeight * y, cb.Height)) {
-
-                                       bool foldable = false;
-                                       if (notEndOfNodes && nodeEnum.Current.StartLine == l) {
-                                               curNode = nodeEnum.Current;
-                                               notEndOfNodes = nodeEnum.MoveNext();
-                                               if (curNode.isFolded) {
-                                                       SyntaxNode nextNode = curNode.NextSiblingOrParentsNextSibling;
-                                                       if (nextNode == null)
-                                                               notEndOfNodes = false;
-                                                       else {
-                                                               while (notEndOfNodes && nodeEnum.Current.StartLine < nextNode.StartLine)
-                                                                       notEndOfNodes = nodeEnum.MoveNext();
-                                                       }
-                                               }
-                                               foldable = true;
+                               while (curLine < doc.LinesCount && printedLines < Math.Min(visibleLines, doc.LinesCount)) {
+                                       
+
+                                       while (notEndOfFolds && foldsEnum.Current.StartLine < curLine) {
+                                               if (foldsEnum.Current.isFolded && curLine <= foldsEnum.Current.EndLine)
+                                                       curLine += foldsEnum.Current.LineCount - 1;
+                                               notEndOfFolds = foldsEnum.MoveNext();
                                        }
 
-                                       //buff = sourceBytes.Slice (lines[l].Start, lines[l].Length);
+                                       if (curLine >= doc.LinesCount)//could it occurs?
+                                               break;  
+                                       
                                        int encodedChar = 0;
+                                       TextLine curTxtLine = doc.GetLine (curLine);
+                                       int tokPtr = doc.FindTokenIndexIncludingPosition(curTxtLine.Start);
+                                       Token tok = doc.Tokens[tokPtr];
 
-                                       while (tok.Start < Document.GetLine (l).End) {
+                                       while (tok.Start < curTxtLine.End) {
                                                buff = sourceBytes.Slice (tok.Start, tok.Length);
                                                gr.SetSource (doc.GetColorForToken (tok.Type));
 
@@ -662,17 +661,14 @@ namespace Crow
                                                        }
 
                                                        if (CurrentToken.Equals(tok)) {
-                                                               /*CharLocation? tokloc = Document.GetLocation  (tok.Start);
-                                                               updateLocation (gr, cb.Width, ref tokloc);*/
                                                                Rectangle r = new RectangleD(pixX, pixY, extents.Width, lineHeight);
                                                                r.Inflate(1);
                                                                gr.Rectangle(r);
-                                                               gr.SetSource(doc.GetColorForToken (tok.Type).AdjustAlpha(0.6));
+                                                               gr.SetSource(doc.GetColorForToken (tok.Type).AdjustAlpha(0.5));
                                                                gr.Stroke();
                                                        }
 
                                                        pixX += extents.XAdvance;
-                                                       x += buff.Length;
                                                }
 
                                                if (++tokPtr >= doc.Tokens.Length)
@@ -681,41 +677,41 @@ namespace Crow
                                        }
 
                                        RectangleD lineRect = new RectangleD (cb.X, pixY, pixX - cb.X, lineHeight);
-                                       if (CurrentNode != null && l >= nodeStart.Value.Line && l <= nodeEnd.Value.Line)
-                                               fillHighlight (gr, l, nodeStart.Value, nodeEnd.Value, lineRect, new Color(0.0,0.1,0.0,0.04));;
+                                       if (CurrentNode != null && curLine >= nodeStart.Value.Line && curLine <= nodeEnd.Value.Line)
+                                               fillHighlight (gr, curLine, nodeStart.Value, nodeEnd.Value, lineRect, new Color(0.0,0.1,0.0,0.06));;
 #if DEBUG_NODES
-                                       if (doc.EditedNode != null && l >= editNodeStart.Value.Line && l <= editNodeEnd.Value.Line)
-                                               fillHighlight (gr, l, editNodeStart.Value, editNodeEnd.Value, lineRect, new Color(0,0.5,0,0.2));;
-                                       if (hoverNode != null && l >= hoverNodeStart.Value.Line && l <= hoverNodeEnd.Value.Line)
-                                               fillHighlight (gr, l, hoverNodeStart.Value, hoverNodeEnd.Value, lineRect, new Color(0,0,0.8,0.1));;
+                                       if (doc.EditedNode != null && curLine >= editNodeStart.Value.Line && l <= editNodeEnd.Value.Line)
+                                               fillHighlight (gr, curLine, editNodeStart.Value, editNodeEnd.Value, lineRect, new Color(0,0.5,0,0.2));;
+                                       if (hoverNode != null && curLine >= hoverNodeStart.Value.Line && curLine <= hoverNodeEnd.Value.Line)
+                                               fillHighlight (gr, curLine, hoverNodeStart.Value, hoverNodeEnd.Value, lineRect, new Color(0,0,0.8,0.1));;
 #endif
-                                       if (selectionNotEmpty && l >= selStart.Line && l <= selEnd.Line)
-                                               fillHighlight (gr, l, selStart, selEnd, lineRect, SelectionBackground);                         
+                                       if (selectionNotEmpty && curLine >= selStart.Line && curLine <= selEnd.Line)
+                                               fillHighlight (gr, curLine, selStart, selEnd, lineRect, SelectionBackground);                           
                                        
                                        //Draw line numbering
                                        if (printLineNumbers){
                                                marginRect.Y = lineRect.Y;
                                                gr.SetSource (marginFG);
 
-                                               drawLineNumber (gr, l, marginRect.X + leftMarginGap + lineNumWidth, marginRect.Y + fe.Ascent);
-                                               if (tokPtr + 1 == doc.Tokens.Length && l < doc.LinesCount-1)
-                                                       drawLineNumber (gr, l+1, marginRect.X + leftMarginGap + lineNumWidth, marginRect.Y + lineHeight + fe.Ascent);
+                                               drawLineNumber (gr, curLine, marginRect.X + leftMarginGap + lineNumWidth, marginRect.Y + fe.Ascent);
+                                               if (tokPtr + 1 == doc.Tokens.Length && curLine < doc.LinesCount-1)
+                                                       drawLineNumber (gr, curLine+1, marginRect.X + leftMarginGap + lineNumWidth, marginRect.Y + lineHeight + fe.Ascent);
                                        }
-                                       
+                                       bool curFoldStart = notEndOfFolds && foldsEnum.Current.StartLine == curLine; 
                                        //draw fold
-                                       if (foldable) {
-                                               Rectangle rFld = new Rectangle (cb.X - leftMarginGap - foldMargin,
+                                       if (curFoldStart) {
+                                               Rectangle rFld = new Rectangle ((int)marginRect.Right - leftMarginGap - foldSize,
                                                        (int)(marginRect.Y + lineHeight / 2.0 - foldSize / 2.0), foldSize, foldSize);
 
                                                gr.Rectangle (rFld);
-                                               if (hoverLoc.HasValue && l == hoverLoc.Value.Line && mouseIsInFoldRect)
+                                               if (hoverLoc.HasValue && curLine == hoverLoc.Value.Line && mouseIsInFoldRect)
                                                        gr.SetSource (Colors.LightBlue);
                                                else
                                                        gr.SetSource (Colors.White);
                                                gr.Fill();
                                                gr.SetSource (Colors.Black);
                                                gr.Rectangle (rFld, 1.0);
-                                               if (curNode.isFolded) {
+                                               if (foldsEnum.Current.isFolded) {
                                                        gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2);
                                                        gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2);
                                                }
@@ -725,49 +721,27 @@ namespace Crow
                                                gr.Stroke ();
                                        }
 
-                                       if (++tokPtr >= doc.Tokens.Length) {
+                                       if (++tokPtr >= doc.Tokens.Length)
                                                break;
-                                       }
-                                               
                                        tok = doc.Tokens[tokPtr];
 
-                                       x = 0;
                                        pixX = cb.Left;
                                        pixY += lineHeight;
-                                       /*if (pixY > cb.Height)
-                                               break;*/
-
-                                       if (foldable && curNode.isFolded) {
-                                               TextSpan ns = curNode.Span;
-                                               l = curNode.StartLine + curNode.LineCount;
-                                               while (tok.End <= Document.GetLine (l).Start) {
-                                                       if (++tokPtr >= doc.Tokens.Length)
-                                                               break;
-                                                       tok = doc.Tokens[tokPtr];
-                                               }
-                                               //tokPtr = doc.FindTokenIndexIncludingPosition (lines[l].Start);
-                                       } else
-                                               l ++;
-                                               /*      } else if (tok2.Type == TokenType.Tabulation) {
-                                                               int spaceRounding = x % tabSize;
-                                                               int spaces = spaceRounding == 0 ?
-                                                                       tabSize * tok2.Length :
-                                                                       spaceRounding + tabSize * (tok2.Length - 1);
-                                                               x += spaces;
-                                                               pixX += spacePixelWidth * spaces;
-                                                               continue;
-                                                       } else if (tok2.Type == TokenType.WhiteSpace) {
-                                                               x += tok2.Length;
-                                                               pixX += spacePixelWidth * tok2.Length;*/
+                                       printedLines++;
+
+                                       if (curFoldStart && foldsEnum.Current.isFolded)
+                                               curLine = foldsEnum.Current.EndLine + 1;
+                                       else
+                                               curLine++;
+
                                }
-                               //gr.Translate (ScrollX, ScrollY);
                        } catch (Exception e) {
                                Console.WriteLine(e.Message);
                                Console.WriteLine(e.StackTrace);
                        } finally {
                                doc.ExitReadLock ();
                        }
-
+                       gr.Translate (ScrollX, 0);
                }
                protected override RectangleD? computeTextCursor (Rectangle cursor) {
                        Rectangle cb = ClientRectangle;
@@ -819,8 +793,9 @@ namespace Crow
                }
                void updateCurrentTokAndNode() {
                        if (currentLoc.HasValue && Document is SourceDocument srcdoc) {
-                               currentTokenIndex = srcdoc.GetAbsolutePosition(currentLoc.Value);
-                               Token tok = srcdoc.FindTokenIncludingPosition(currentTokenIndex);
+                               int pos = srcdoc.GetAbsolutePosition(currentLoc.Value);
+                               currentTokenIndex = srcdoc.FindTokenIndexIncludingPosition(pos);
+                               Token tok = srcdoc.GetTokenByIndex(currentTokenIndex);
                                CurrentNode = srcdoc.Root?.FindNodeIncludingSpan(tok.Span);
                                
                                NotifyValueChanged("CurrentToken",tok);
index b4c6eb1dfe7d0fe76b67a75f8bb1191811cf7e73..4d6981ed2fe18c89a8c2c17ae0db545774c66666 100644 (file)
@@ -88,6 +88,7 @@ namespace CrowEditBase
                }
                public CharLocation GetLocation (int absolutePosition) => lines.GetLocation (absolutePosition);
                public TextLine GetLine (int index) => lines[index];
+               public void SetLine (int index, TextLine line) => lines[index] = line;
                public ReadOnlySpan<char> GetText (TextLine line) => GetText(line.Span);
                public ReadOnlySpan<char> GetText (TextSpan textSpan) => buffer.Span.Slice(textSpan.Start, textSpan.Length);
                public int GetAbsolutePosition (CharLocation loc) => lines.GetAbsolutePosition (loc);
index 1843dee2315d53050f6904faa98a3a8ac484c760..a7c91b1e1c7aa5b669224b9d6c7772ab2eefa1c1 100644 (file)
@@ -250,6 +250,14 @@ namespace CrowEditBase
                                documentRWLock.ExitReadLock();
                        }
                }
+               public void SetLine (int index, TextLine newValue) {
+                       documentRWLock.EnterReadLock ();
+                       try {
+                               buffer.SetLine(index, newValue);
+                       } finally {
+                               documentRWLock.ExitReadLock();
+                       }
+               }               
                public ReadOnlySpan<char> GetLineText (int index) {
                        documentRWLock.EnterReadLock ();
                        try {
index a48dd48a8359061eea743d867393f3a1f72c2501..47b6598ce16d596344d599cad1ba146941305bdf 100644 (file)
@@ -31,7 +31,7 @@ Editor {
        Width="Stretched";
        Background="White";
        Foreground="Black";
-       MouseWheelSpeed = "20";
+       MouseWheelSpeed = "5";
        BubbleEvents ="None";
        ClipToClientRect = "true";
        MouseCursor = "ibeam";