Procházet zdrojové kódy

C#: Fix very slow build log update in the editor

(cherry picked from commit b0eb9061e41db87a906ae7ecb14ad1e755058fcb)
Ignacio Etcheverry před 4 roky
rodič
revize
c5acdfb5f5

+ 31 - 8
modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs

@@ -2,6 +2,7 @@ using Godot;
 using System;
 using Godot.Collections;
 using GodotTools.Internals;
+using JetBrains.Annotations;
 using File = GodotTools.Utils.File;
 using Path = System.IO.Path;
 
@@ -26,8 +27,10 @@ namespace GodotTools.Build
         private TextEdit buildLog;
         private PopupMenu issuesListContextMenu;
 
-        [Signal]
-        public delegate void BuildStateChanged();
+        private readonly object pendingBuildLogTextLock = new object();
+        [NotNull] private string pendingBuildLogText = string.Empty;
+
+        [Signal] public event Action BuildStateChanged;
 
         public bool HasBuildExited { get; private set; } = false;
 
@@ -241,16 +244,34 @@ namespace GodotTools.Build
             EmitSignal(nameof(BuildStateChanged));
         }
 
+        private void UpdateBuildLogText()
+        {
+            lock (pendingBuildLogTextLock)
+            {
+                buildLog.Text += pendingBuildLogText;
+                pendingBuildLogText = string.Empty;
+                ScrollToLastNonEmptyLogLine();
+            }
+        }
+
         private void StdOutputReceived(string text)
         {
-            buildLog.Text += text + "\n";
-            ScrollToLastNonEmptyLogLine();
+            lock (pendingBuildLogTextLock)
+            {
+                if (pendingBuildLogText.Length == 0)
+                    CallDeferred(nameof(UpdateBuildLogText));
+                pendingBuildLogText += text + "\n";
+            }
         }
 
         private void StdErrorReceived(string text)
         {
-            buildLog.Text += text + "\n";
-            ScrollToLastNonEmptyLogLine();
+            lock (pendingBuildLogTextLock)
+            {
+                if (pendingBuildLogText.Length == 0)
+                    CallDeferred(nameof(UpdateBuildLogText));
+                pendingBuildLogText += text + "\n";
+            }
         }
 
         private void ScrollToLastNonEmptyLogLine()
@@ -378,12 +399,14 @@ namespace GodotTools.Build
             BuildManager.BuildStarted += BuildStarted;
             BuildManager.BuildFinished += BuildFinished;
             // StdOutput/Error can be received from different threads, so we need to use CallDeferred
-            BuildManager.StdOutputReceived += line => CallDeferred(nameof(StdOutputReceived), line);
-            BuildManager.StdErrorReceived += line => CallDeferred(nameof(StdErrorReceived), line);
+            BuildManager.StdOutputReceived += StdOutputReceived;
+            BuildManager.StdErrorReceived += StdErrorReceived;
         }
 
         public void OnBeforeSerialize()
         {
+            // In case it didn't update yet. We don't want to have to serialize any pending output.
+            UpdateBuildLogText();
         }
 
         public void OnAfterDeserialize()