From e248cd9b667200522158c2807c1e96b4b61d2f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Wed, 14 Mar 2018 18:13:12 +0100 Subject: Fixes VSTS 581661: [Feedback] /* */ Comments slow or non responsive https://devdiv.visualstudio.com/DevDiv/_workitems/edit/581661 Seems that a span change detection was missing completely - that this worked in former versions must've been a side effect. I took the chance to ensure that highlighting is really done in background which looks ok on my systems. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 47 +++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index f750fcd8b1..d483d9b09a 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -1340,7 +1340,7 @@ namespace Mono.TextEditor this.Chunk = chunk; } } - Dictionary cachedLines = new Dictionary (); + ImmutableDictionary cachedLines = ImmutableDictionary.Empty; CancellationTokenSource cacheSrc = new CancellationTokenSource (); Tuple, bool> GetCachedChunks (TextDocument doc, DocumentLine line, int offset, int length) { @@ -1351,18 +1351,45 @@ namespace Mono.TextEditor return Tuple.Create (TrimChunks (result.Segments, offset - line.Offset, length), true); } var token = cacheSrc.Token; - var task = doc.SyntaxMode.GetHighlightedLineAsync (line, token); - if (task.IsCompleted) { - cachedLines [lineNumber] = task.Result; - return Tuple.Create (TrimChunks (task.Result.Segments, offset - line.Offset, length), true); - } - task.ContinueWith (t => { - cachedLines [lineNumber] = t.Result; - Document.CommitLineUpdate (lineNumber); // Required for highlighting updates - }, token, TaskContinuationOptions.OnlyOnRanToCompletion, Runtime.MainTaskScheduler); + var task = Task.Run(async delegate { + var highlightedLine = await doc.SyntaxMode.GetHighlightedLineAsync (line, token); + cachedLines = cachedLines.SetItem (lineNumber, highlightedLine); + int curLineNumber = lineNumber + 1; + var curLine = line.NextLine; + while (curLine != null) { + if (cachedLines.TryGetValue (curLineNumber, out HighlightedLine highlightedCurLine) && highlightedCurLine?.TextSegment.Length == curLine.Length) { + var updatedCurLine = await doc.SyntaxMode.GetHighlightedLineAsync (curLine, token); + if (!LinesAreEqual(highlightedCurLine, updatedCurLine)) { + cachedLines = cachedLines.SetItem (curLineNumber, updatedCurLine); + } else { + break; + } + }else { + break; + } + curLineNumber++; + curLine = curLine.NextLine; + } + Runtime.RunInMainThread (delegate { + Document.CommitMultipleLineUpdate (lineNumber, curLineNumber - 1); + }); + }); return Tuple.Create (new List (new [] { new ColoredSegment (0, line.Length, ScopeStack.Empty) }), false); } + static bool LinesAreEqual (HighlightedLine line1, HighlightedLine line2) + { + if (line1.Segments.Count != line2.Segments.Count) + return false; + for (int i = 0; i < line1.Segments.Count; i++) { + var seg1 = line1.Segments [i]; + var seg2 = line2.Segments [i]; + if (seg1.Length != seg2.Length || seg1.ColorStyleKey != seg2.ColorStyleKey) + return false; + } + return true; + } + internal static List TrimChunks (IReadOnlyList segments, int offset, int length) { var result = new List (); -- cgit v1.2.3 From 1babbdb34571fc91aac491b0f86d24480dfdaf1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 16 Mar 2018 09:08:20 +0100 Subject: [SourceEditor] Text view margin update is now more eager on state change. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index d483d9b09a..97513fe8a3 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -1356,21 +1356,17 @@ namespace Mono.TextEditor cachedLines = cachedLines.SetItem (lineNumber, highlightedLine); int curLineNumber = lineNumber + 1; var curLine = line.NextLine; - while (curLine != null) { - if (cachedLines.TryGetValue (curLineNumber, out HighlightedLine highlightedCurLine) && highlightedCurLine?.TextSegment.Length == curLine.Length) { - var updatedCurLine = await doc.SyntaxMode.GetHighlightedLineAsync (curLine, token); - if (!LinesAreEqual(highlightedCurLine, updatedCurLine)) { - cachedLines = cachedLines.SetItem (curLineNumber, updatedCurLine); - } else { - break; - } - }else { - break; + if (cachedLines.TryGetValue (curLineNumber, out HighlightedLine highlightedCurLine) && highlightedCurLine?.TextSegment.Length == curLine.Length) { + var updatedCurLine = await doc.SyntaxMode.GetHighlightedLineAsync (curLine, token); + if (!LinesAreEqual(highlightedCurLine, updatedCurLine)) { + cachedLines = cachedLines.SetItem (curLineNumber, updatedCurLine); + await Runtime.RunInMainThread (delegate { + Document.CommitMultipleLineUpdate (lineNumber, lineNumber + (int)(textEditor.Allocation.Height / textEditor.LineHeight) + 1); + }); + return; } - curLineNumber++; - curLine = curLine.NextLine; } - Runtime.RunInMainThread (delegate { + await Runtime.RunInMainThread (delegate { Document.CommitMultipleLineUpdate (lineNumber, curLineNumber - 1); }); }); -- cgit v1.2.3 From 8f8a456bf16cf304185768e7653c4232ada45f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 16 Mar 2018 16:48:00 +0100 Subject: [SourceEditor] Implemented other apporach to fix the update issue. This way it's a bit less complex. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 49 ++++++++++------------ .../ISyntaxHighlighting.cs | 17 +++++++- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index 97513fe8a3..51b101c6a2 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -1340,7 +1340,7 @@ namespace Mono.TextEditor this.Chunk = chunk; } } - ImmutableDictionary cachedLines = ImmutableDictionary.Empty; + Dictionary cachedLines = new Dictionary (); CancellationTokenSource cacheSrc = new CancellationTokenSource (); Tuple, bool> GetCachedChunks (TextDocument doc, DocumentLine line, int offset, int length) { @@ -1351,39 +1351,32 @@ namespace Mono.TextEditor return Tuple.Create (TrimChunks (result.Segments, offset - line.Offset, length), true); } var token = cacheSrc.Token; - var task = Task.Run(async delegate { - var highlightedLine = await doc.SyntaxMode.GetHighlightedLineAsync (line, token); - cachedLines = cachedLines.SetItem (lineNumber, highlightedLine); - int curLineNumber = lineNumber + 1; - var curLine = line.NextLine; - if (cachedLines.TryGetValue (curLineNumber, out HighlightedLine highlightedCurLine) && highlightedCurLine?.TextSegment.Length == curLine.Length) { - var updatedCurLine = await doc.SyntaxMode.GetHighlightedLineAsync (curLine, token); - if (!LinesAreEqual(highlightedCurLine, updatedCurLine)) { - cachedLines = cachedLines.SetItem (curLineNumber, updatedCurLine); - await Runtime.RunInMainThread (delegate { - Document.CommitMultipleLineUpdate (lineNumber, lineNumber + (int)(textEditor.Allocation.Height / textEditor.LineHeight) + 1); - }); - return; - } + var task = doc.SyntaxMode.GetHighlightedLineAsync (line, token); + if (task.IsCompleted) { + if (result != null && ShouldUpdateSpan (result, task.Result)) + textEditor.QueueDraw (); + cachedLines [lineNumber] = task.Result; + return Tuple.Create (TrimChunks (task.Result.Segments, offset - line.Offset, length), true); + } + task.ContinueWith (t => { + cachedLines [lineNumber] = t.Result; + if (result != null && ShouldUpdateSpan (result, t.Result)) { + textEditor.QueueDraw (); + } else { + Document.CommitLineUpdate (line); } - await Runtime.RunInMainThread (delegate { - Document.CommitMultipleLineUpdate (lineNumber, curLineNumber - 1); - }); - }); + }, token, TaskContinuationOptions.OnlyOnRanToCompletion, Runtime.MainTaskScheduler); return Tuple.Create (new List (new [] { new ColoredSegment (0, line.Length, ScopeStack.Empty) }), false); } - static bool LinesAreEqual (HighlightedLine line1, HighlightedLine line2) + static bool ShouldUpdateSpan (HighlightedLine line1, HighlightedLine line2) { - if (line1.Segments.Count != line2.Segments.Count) - return false; - for (int i = 0; i < line1.Segments.Count; i++) { - var seg1 = line1.Segments [i]; - var seg2 = line2.Segments [i]; - if (seg1.Length != seg2.Length || seg1.ColorStyleKey != seg2.ColorStyleKey) - return false; + if (line1.IsContinuedBeyondLineEnd != line2.IsContinuedBeyondLineEnd) + return true; + if (line1.IsContinuedBeyondLineEnd == true) { + return line1.Segments.Last ().ScopeStack.Peek () != line2.Segments.Last ().ScopeStack.Peek (); } - return true; + return false; } internal static List TrimChunks (IReadOnlyList segments, int offset, int length) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs index 34b6f7d4f3..215e49ba47 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs @@ -31,6 +31,7 @@ using MonoDevelop.Core.Text; using System.Collections.Immutable; using System.Threading.Tasks; using System.Threading; +using System.Linq; namespace MonoDevelop.Ide.Editor.Highlighting { @@ -41,6 +42,20 @@ namespace MonoDevelop.Ide.Editor.Highlighting /// The segment offsets are 0 at line start regardless of where the line is inside the document. /// public IReadOnlyList Segments { get; private set; } + + bool? isContinuedBeyondLineEnd; + public bool? IsContinuedBeyondLineEnd { + get { + if (isContinuedBeyondLineEnd.HasValue) + return isContinuedBeyondLineEnd.Value; + var result = Segments.Count > 0 ? TextSegment.Length < Segments.Last ().EndOffset : false; + return isContinuedBeyondLineEnd = result; + } + set { + isContinuedBeyondLineEnd = value; + } + } + public HighlightedLine (ISegment textSegment, IReadOnlyList segments) { TextSegment = textSegment; @@ -89,4 +104,4 @@ namespace MonoDevelop.Ide.Editor.Highlighting { } } -} \ No newline at end of file +} -- cgit v1.2.3 From a23b958fd470f299b6a6d2bc871ecd755aceb4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 19 Mar 2018 10:47:37 +0100 Subject: [SourceEditor] Fixed text mate highlighting. The text mate based highlighting was broken as well. And streamlined the text view highlighting recognition changes. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 40 +++++++++++++++++----- .../Document/DocumentUpdateRequest.cs | 4 --- .../SyntaxHighlighting.cs | 6 ++-- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index 51b101c6a2..150cb8a81b 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -332,7 +332,6 @@ namespace Mono.TextEditor { for (int i = 0; i < e.TextChanges.Count; ++i) { var change = e.TextChanges[i]; - RemoveCachedLine (Document.OffsetToLineNumber (change.NewOffset)); if (mouseSelectionMode == MouseSelectionMode.Word && change.Offset < mouseWordStart) { int delta = change.ChangeDelta; mouseWordStart += delta; @@ -1322,12 +1321,27 @@ namespace Mono.TextEditor cacheSrc = new CancellationTokenSource (); cachedLines.Clear (); } - public void PurgeLayoutCache () { DisposeLayoutDict (); } + void PurgeLayoutCacheAfter (int lineNumber) + { + foreach (var descr in layoutDict.ToArray()) { + if (descr.Key >= lineNumber) { + descr.Value.Dispose (); + layoutDict.Remove (descr.Key); + } + } + + foreach (var descr in cachedLines.ToArray()) { + if (descr.Key >= lineNumber) { + cachedLines.Remove (descr.Key); + } + } + } + class ChunkDescriptor : LineDescriptor { public List Chunk { @@ -1353,22 +1367,30 @@ namespace Mono.TextEditor var token = cacheSrc.Token; var task = doc.SyntaxMode.GetHighlightedLineAsync (line, token); if (task.IsCompleted) { - if (result != null && ShouldUpdateSpan (result, task.Result)) - textEditor.QueueDraw (); - cachedLines [lineNumber] = task.Result; + UpdateLineHighlight (lineNumber, result, task.Result); return Tuple.Create (TrimChunks (task.Result.Segments, offset - line.Offset, length), true); } task.ContinueWith (t => { - cachedLines [lineNumber] = t.Result; - if (result != null && ShouldUpdateSpan (result, t.Result)) { - textEditor.QueueDraw (); - } else { + if (UpdateLineHighlight (lineNumber, result, t.Result)) { + RemoveCachedLine (lineNumber) Document.CommitLineUpdate (line); } }, token, TaskContinuationOptions.OnlyOnRanToCompletion, Runtime.MainTaskScheduler); return Tuple.Create (new List (new [] { new ColoredSegment (0, line.Length, ScopeStack.Empty) }), false); } + bool UpdateLineHighlight (int lineNumber, HighlightedLine oldLine, HighlightedLine newLine) + { + if (oldLine != null && ShouldUpdateSpan (oldLine, newLine)) { + PurgeLayoutCacheAfter (lineNumber); + cachedLines [lineNumber] = newLine; + textEditor.QueueDraw (); + return false; + } + cachedLines [lineNumber] = newLine; + return true; + } + static bool ShouldUpdateSpan (HighlightedLine line1, HighlightedLine line2) { if (line1.IsContinuedBeyondLineEnd != line2.IsContinuedBeyondLineEnd) diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs index 2cd7c20c7c..dded9bdb91 100644 --- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs +++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs @@ -84,12 +84,8 @@ namespace Mono.TextEditor public override void Update (MonoTextEditor editor) { if (start == end) { - editor.TextViewMargin.RemoveCachedLine (start); editor.RedrawLine (start); } else { - for (int i = start; i <= end; i++) { - editor.TextViewMargin.RemoveCachedLine (i); - } editor.RedrawLines (start, end); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs index c8340e77e8..153a651a5a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs @@ -188,7 +188,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting int lastMatch = -1; var highlightedSegment = new TextSegment (startOffset, length); string lineText = text.GetTextAt (startOffset, length); - + var initialState = state.Clone (); int timeoutOccursAt; unchecked { timeoutOccursAt = Environment.TickCount + (int)matchTimeout.TotalMilliseconds; @@ -330,7 +330,9 @@ namespace MonoDevelop.Ide.Editor.Highlighting segments.Add (new ColoredSegment (curSegmentOffset, endOffset - curSegmentOffset, ScopeStack)); } - return Task.FromResult (new HighlightedLine (highlightedSegment, segments)); + return Task.FromResult (new HighlightedLine (highlightedSegment, segments) { + IsContinuedBeyondLineEnd = !initialState.Equals (state) + }); } void PushStack (SyntaxMatch curMatch, IEnumerable nextContexts) -- cgit v1.2.3 From 5eb4a209f2e466a9bcd2a2099bd2f5cbb26cff77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 19 Mar 2018 14:27:10 +0100 Subject: [SourceEditor] Handle null case. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index 150cb8a81b..ca15510bb5 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -1367,12 +1367,16 @@ namespace Mono.TextEditor var token = cacheSrc.Token; var task = doc.SyntaxMode.GetHighlightedLineAsync (line, token); if (task.IsCompleted) { - UpdateLineHighlight (lineNumber, result, task.Result); - return Tuple.Create (TrimChunks (task.Result.Segments, offset - line.Offset, length), true); + if (task.Result != null) { + UpdateLineHighlight (lineNumber, result, task.Result); + return Tuple.Create (TrimChunks (task.Result.Segments, offset - line.Offset, length), true); + } } task.ContinueWith (t => { + if (t.Result == null) + return; if (UpdateLineHighlight (lineNumber, result, t.Result)) { - RemoveCachedLine (lineNumber) + RemoveCachedLine (lineNumber); Document.CommitLineUpdate (line); } }, token, TaskContinuationOptions.OnlyOnRanToCompletion, Runtime.MainTaskScheduler); -- cgit v1.2.3