浏览代码

Sujith :) ->
1. Basic functionality and gui improvements

Sujith:) 1 月之前
父节点
当前提交
50a784b72a

+ 3 - 0
Assets/Arbitrator/Editor/GUI.meta

@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 4e20dcb128634a39848edad51202eb5c
+timeCreated: 1750158506

+ 81 - 25
Assets/Arbitrator/Editor/ArbitratorWindow.cs

@@ -14,9 +14,10 @@ using System.Linq;
 using UnityEngine;
 using UnityEngine;
 using UnityEditor;
 using UnityEditor;
 using LibGit2Sharp;
 using LibGit2Sharp;
+using Terra.Arbitrator.Services;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.GUI
 {
 {
     public class ArbitratorWindow : EditorWindow
     public class ArbitratorWindow : EditorWindow
     {
     {
@@ -27,6 +28,8 @@ namespace Terra.Arbitrator
         private string _errorMessage;
         private string _errorMessage;
         private bool _isLoading;
         private bool _isLoading;
         private string _loadingMessage = "";
         private string _loadingMessage = "";
+        private GUIStyle _evenRowStyle;
+        private bool _stylesInitialized;
 
 
         [MenuItem("Terra/Changes")]
         [MenuItem("Terra/Changes")]
         public static void ShowWindow()
         public static void ShowWindow()
@@ -43,9 +46,35 @@ namespace Terra.Arbitrator
         {
         {
             HandleCompare();
             HandleCompare();
         }
         }
+        
+        /// <summary>
+        /// Initializes custom GUIStyles. We do this here to avoid creating new
+        /// styles and textures on every OnGUI call, which is inefficient.
+        /// </summary>
+        private void InitializeStyles()
+        {
+            if (_stylesInitialized) return;
+
+            _evenRowStyle = new GUIStyle();
+            
+            // Create a 1x1 texture with a subtle gray color
+            var texture = new Texture2D(1, 1);
+            // Use a slightly different color depending on the editor skin (light/dark)
+            var color = EditorGUIUtility.isProSkin 
+                ? new Color(0.3f, 0.3f, 0.3f, 0.3f) 
+                : new Color(0.8f, 0.8f, 0.8f, 0.5f);
+            texture.SetPixel(0, 0, color);
+            texture.Apply();
+            
+            _evenRowStyle.normal.background = texture;
+            
+            _stylesInitialized = true;
+        }
 
 
         private void OnGUI()
         private void OnGUI()
         {
         {
+            InitializeStyles();
+            
             // --- Top Toolbar ---
             // --- Top Toolbar ---
             DrawToolbar();
             DrawToolbar();
             
             
@@ -63,11 +92,7 @@ namespace Terra.Arbitrator
             }
             }
 
 
             // --- Main Content ---
             // --- Main Content ---
-            if (_isLoading)
-            {
-                // You can add a more prominent loading indicator here if you wish
-            }
-            else if (_changes is { Count: > 0 })
+            else if (!_isLoading && _changes is { Count: > 0 })
             {
             {
                 DrawChangesList();
                 DrawChangesList();
                 DrawCommitSection();
                 DrawCommitSection();
@@ -86,13 +111,27 @@ namespace Terra.Arbitrator
         private void DrawToolbar()
         private void DrawToolbar()
         {
         {
             EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
             EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
-
+            EditorGUI.BeginDisabledGroup(_isLoading);
             // The refresh button is now on the toolbar
             // The refresh button is now on the toolbar
             if (GUILayout.Button(new GUIContent("Refresh", EditorGUIUtility.IconContent("Refresh").image, "Fetches the latest status from the remote."), EditorStyles.toolbarButton, GUILayout.Width(80)))
             if (GUILayout.Button(new GUIContent("Refresh", EditorGUIUtility.IconContent("Refresh").image, "Fetches the latest status from the remote."), EditorStyles.toolbarButton, GUILayout.Width(80)))
             {
             {
                 HandleCompare();
                 HandleCompare();
             }
             }
             
             
+            if (_changes != null && _changes.Count > 0)
+            {
+                if (GUILayout.Button("Select All", EditorStyles.toolbarButton, GUILayout.Width(80)))
+                {
+                    SetAllSelection(true);
+                }
+                if (GUILayout.Button("Deselect All", EditorStyles.toolbarButton, GUILayout.Width(80)))
+                {
+                    SetAllSelection(false);
+                }
+            }
+            
+            EditorGUI.EndDisabledGroup();
+            
             // This pushes everything that comes after it to the right.
             // This pushes everything that comes after it to the right.
             GUILayout.FlexibleSpace();
             GUILayout.FlexibleSpace();
 
 
@@ -107,6 +146,15 @@ namespace Terra.Arbitrator
 
 
             EditorGUILayout.EndHorizontal();
             EditorGUILayout.EndHorizontal();
         }
         }
+        
+        private void SetAllSelection(bool selected)
+        {
+            if (_changes == null) return;
+            foreach (var change in _changes)
+            {
+                change.IsSelectedForCommit = selected;
+            }
+        }
 
 
         private void HandleCompare()
         private void HandleCompare()
         {
         {
@@ -222,45 +270,52 @@ namespace Terra.Arbitrator
 
 
             // --- Draw Scrollable List ---
             // --- Draw Scrollable List ---
             _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.ExpandHeight(true));
             _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.ExpandHeight(true));
-            foreach (var change in _changes)
+            for (var i = 0; i < _changes.Count; i++)
             {
             {
-                EditorGUILayout.BeginHorizontal();
+                var change = _changes[i];
+                // Use the evenRowStyle for every second row (i % 2 == 0), otherwise use no style.
+                var rowStyle = i % 2 == 0 ? _evenRowStyle : GUIStyle.none;
+                
+                EditorGUILayout.BeginHorizontal(rowStyle);
 
 
-                // Column 1: Toggle Box
                 change.IsSelectedForCommit = EditorGUILayout.Toggle(change.IsSelectedForCommit, GUILayout.Width(45));
                 change.IsSelectedForCommit = EditorGUILayout.Toggle(change.IsSelectedForCommit, GUILayout.Width(45));
-
-                // Column 2: Status
+                
                 string status;
                 string status;
                 Color statusColor;
                 Color statusColor;
+                string filePathDisplay;
+
                 switch (change.Status)
                 switch (change.Status)
                 {
                 {
-                    case ChangeKind.Added: status = "[+]"; statusColor = Color.green; break;
-                    case ChangeKind.Deleted: status = "[-]"; statusColor = Color.red; break;
-                    case ChangeKind.Modified: status = "[M]"; statusColor = new Color(1.0f, 0.6f, 0.0f); break;
+                    case ChangeKind.Added: 
+                        status = "[+]"; statusColor = Color.green; filePathDisplay = change.FilePath; break;
+                    case ChangeKind.Deleted: 
+                        status = "[-]"; statusColor = Color.red; filePathDisplay = change.FilePath; break;
+                    case ChangeKind.Modified: 
+                        status = "[M]"; statusColor = new Color(1.0f, 0.6f, 0.0f); filePathDisplay = change.FilePath; break;
+                    case ChangeKind.Renamed: 
+                        status = "[R]"; statusColor = new Color(0.6f, 0.6f, 1.0f);
+                        filePathDisplay = $"{change.OldFilePath} -> {change.FilePath}"; break;
                     case ChangeKind.Unmodified:
                     case ChangeKind.Unmodified:
-                    case ChangeKind.Renamed:
                     case ChangeKind.Copied:
                     case ChangeKind.Copied:
                     case ChangeKind.Ignored:
                     case ChangeKind.Ignored:
                     case ChangeKind.Untracked:
                     case ChangeKind.Untracked:
                     case ChangeKind.TypeChanged:
                     case ChangeKind.TypeChanged:
                     case ChangeKind.Unreadable:
                     case ChangeKind.Unreadable:
                     case ChangeKind.Conflicted:
                     case ChangeKind.Conflicted:
-                        status = "[C]"; statusColor = new Color(0.5f, 0.5f, 0.5f, 0.3f); break;
-                    default: status = "[?]"; statusColor = Color.white; break;
+                    default: 
+                        status = "[?]"; statusColor = Color.white; filePathDisplay = change.FilePath; break;
                 }
                 }
-                var originalColor = GUI.color;
-                GUI.color = statusColor;
+                
+                var originalColor = UnityEngine.GUI.color;
+                UnityEngine.GUI.color = statusColor;
                 EditorGUILayout.LabelField(new GUIContent(status, change.Status.ToString()), GUILayout.Width(50));
                 EditorGUILayout.LabelField(new GUIContent(status, change.Status.ToString()), GUILayout.Width(50));
-                GUI.color = originalColor;
+                UnityEngine.GUI.color = originalColor;
 
 
-                // Column 3: File Path
-                EditorGUILayout.LabelField(new GUIContent(change.FilePath, change.FilePath));
+                EditorGUILayout.LabelField(new GUIContent(filePathDisplay, filePathDisplay));
 
 
-                // Column 4: Reset Button
                 EditorGUI.BeginDisabledGroup(_isLoading);
                 EditorGUI.BeginDisabledGroup(_isLoading);
                 if (GUILayout.Button(new GUIContent("Reset", "Revert changes for this file"), GUILayout.Width(55)))
                 if (GUILayout.Button(new GUIContent("Reset", "Revert changes for this file"), GUILayout.Width(55)))
                 {
                 {
-                    // Defers the action to avoid GUI layout errors
                     EditorApplication.delayCall += () => HandleResetFile(change);
                     EditorApplication.delayCall += () => HandleResetFile(change);
                 }
                 }
                 EditorGUI.EndDisabledGroup();
                 EditorGUI.EndDisabledGroup();
@@ -281,6 +336,7 @@ namespace Terra.Arbitrator
             EditorGUI.BeginDisabledGroup(isPushDisabled);
             EditorGUI.BeginDisabledGroup(isPushDisabled);
             if (GUILayout.Button("Commit & Push Selected Files", GUILayout.Height(40)))
             if (GUILayout.Button("Commit & Push Selected Files", GUILayout.Height(40)))
             {
             {
+                Debug.Log("Commit & Push Selected Files");
                 HandleCommitAndPush();
                 HandleCommitAndPush();
             }
             }
             EditorGUI.EndDisabledGroup();
             EditorGUI.EndDisabledGroup();

Assets/Arbitrator/Editor/ArbitratorWindow.cs.meta → Assets/Arbitrator/Editor/GUI/ArbitratorWindow.cs.meta


+ 27 - 13
Assets/Arbitrator/Editor/DiffWindow.cs

@@ -8,7 +8,7 @@ using System.IO;
 using UnityEditor;
 using UnityEditor;
 using UnityEngine;
 using UnityEngine;
 
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.GUI
 {
 {
     public class DiffWindow : EditorWindow
     public class DiffWindow : EditorWindow
     {
     {
@@ -16,7 +16,8 @@ namespace Terra.Arbitrator
         private string _diffContent;
         private string _diffContent;
         private Action<bool> _onCloseCallback;
         private Action<bool> _onCloseCallback;
         private Vector2 _scrollPosition;
         private Vector2 _scrollPosition;
-        private bool _callbackInvoked = false;
+        private bool _callbackInvoked;
+        private GUIStyle _diffStyle;
 
 
         /// <summary>
         /// <summary>
         /// Shows a modal window to display the diff and get user confirmation.
         /// Shows a modal window to display the diff and get user confirmation.
@@ -26,7 +27,7 @@ namespace Terra.Arbitrator
         /// <param name="onCloseCallback">A callback that returns true if the user confirmed, otherwise false.</param>
         /// <param name="onCloseCallback">A callback that returns true if the user confirmed, otherwise false.</param>
         public static void ShowWindow(string filePath, string diffContent, Action<bool> onCloseCallback)
         public static void ShowWindow(string filePath, string diffContent, Action<bool> onCloseCallback)
         {
         {
-            DiffWindow window = GetWindow<DiffWindow>(true, "Diff Viewer", true);
+            var window = GetWindow<DiffWindow>(true, "Diff Viewer", true);
             window.titleContent = new GUIContent($"Diff: {Path.GetFileName(filePath)}");
             window.titleContent = new GUIContent($"Diff: {Path.GetFileName(filePath)}");
             window.minSize = new Vector2(700, 500);
             window.minSize = new Vector2(700, 500);
             window._filePath = filePath;
             window._filePath = filePath;
@@ -36,19 +37,33 @@ namespace Terra.Arbitrator
             window.ShowModalUtility(); // Show as a blocking modal window
             window.ShowModalUtility(); // Show as a blocking modal window
         }
         }
 
 
-        private void OnGUI()
+        private void OnEnable()
         {
         {
-            EditorGUILayout.LabelField(_filePath, EditorStyles.boldLabel);
-
-            // Create a custom style for the diff text for better readability
-            var diffStyle = new GUIStyle(EditorStyles.textArea)
+            // Initialize the style here to avoid doing it every OnGUI call.
+            _diffStyle = new GUIStyle(EditorStyles.label)
             {
             {
                 richText = true,
                 richText = true,
-                wordWrap = false
+                wordWrap = false,
+                alignment = TextAnchor.UpperLeft
             };
             };
+        }
+
+        private void OnGUI()
+        {
+            EditorGUILayout.LabelField(_filePath, EditorStyles.boldLabel);
+
+            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, EditorStyles.helpBox);
             
             
-            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, EditorStyles.helpBox, GUILayout.ExpandHeight(true));
-            EditorGUILayout.SelectableLabel(GetColoredDiff(_diffContent), diffStyle, GUILayout.ExpandHeight(true));
+            var coloredText = GetColoredDiff(_diffContent);
+            var content = new GUIContent(coloredText);
+            
+            // Calculate the required height based on the window's width, accounting for scrollbar and padding.
+            var viewWidth = EditorGUIUtility.currentViewWidth - 30; // Approximate width inside scroll view
+            var requiredHeight = _diffStyle.CalcHeight(content, viewWidth);
+            
+            // Use GUILayout.Label with an explicit height to ensure the ScrollView's content area is sized correctly.
+            EditorGUILayout.SelectableLabel(coloredText, _diffStyle, GUILayout.MinHeight(requiredHeight));
+
             EditorGUILayout.EndScrollView();
             EditorGUILayout.EndScrollView();
 
 
             EditorGUILayout.Space();
             EditorGUILayout.Space();
@@ -64,7 +79,6 @@ namespace Terra.Arbitrator
             }
             }
             if (GUILayout.Button("Cancel", GUILayout.Height(30), GUILayout.Width(120)))
             if (GUILayout.Button("Cancel", GUILayout.Height(30), GUILayout.Width(120)))
             {
             {
-                // Let OnDestroy handle the callback
                 Close();
                 Close();
             }
             }
             EditorGUILayout.EndHorizontal();
             EditorGUILayout.EndHorizontal();
@@ -93,7 +107,7 @@ namespace Terra.Arbitrator
                     coloredDiff += $"{line}\n";
                     coloredDiff += $"{line}\n";
                 }
                 }
             }
             }
-            return coloredDiff;
+            return coloredDiff + "\n";
         }
         }
 
 
         private void OnDestroy()
         private void OnDestroy()

Assets/Arbitrator/Editor/DiffWindow.cs.meta → Assets/Arbitrator/Editor/GUI/DiffWindow.cs.meta


+ 3 - 0
Assets/Arbitrator/Editor/Services.meta

@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1f5105621a714595bebcd961c832ac63
+timeCreated: 1750158525

+ 5 - 3
Assets/Arbitrator/Editor/GitChange.cs

@@ -10,7 +10,7 @@
 
 
 using LibGit2Sharp;
 using LibGit2Sharp;
 
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.Services
 {
 {
     /// <summary>
     /// <summary>
     /// A data container for a single file change detected by Git.
     /// A data container for a single file change detected by Git.
@@ -18,6 +18,7 @@ namespace Terra.Arbitrator
     public class GitChange
     public class GitChange
     {
     {
         public string FilePath { get; private set; }
         public string FilePath { get; private set; }
+        public string OldFilePath { get; private set; }
         public ChangeKind Status { get; private set; }
         public ChangeKind Status { get; private set; }
         
         
         /// <summary>
         /// <summary>
@@ -25,9 +26,10 @@ namespace Terra.Arbitrator
         /// </summary>
         /// </summary>
         public bool IsSelectedForCommit { get; set; }
         public bool IsSelectedForCommit { get; set; }
 
 
-        public GitChange(string filePath, ChangeKind status)
+        public GitChange(string newPath, string oldPath, ChangeKind status)
         {
         {
-            FilePath = filePath;
+            FilePath = newPath;
+            OldFilePath = oldPath;
             Status = status;
             Status = status;
             IsSelectedForCommit = true; // Default to select
             IsSelectedForCommit = true; // Default to select
         }
         }

Assets/Arbitrator/Editor/GitChange.cs.meta → Assets/Arbitrator/Editor/Services/GitChange.cs.meta


+ 33 - 7
Assets/Arbitrator/Editor/GitService.cs

@@ -5,12 +5,12 @@
 
 
 using System;
 using System;
 using System.IO;
 using System.IO;
-using UnityEngine;
 using LibGit2Sharp;
 using LibGit2Sharp;
+using UnityEngine;
 using Terra.Arbitrator.Promises;
 using Terra.Arbitrator.Promises;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.Services
 {
 {
     public static class GitService
     public static class GitService
     {
     {
@@ -68,9 +68,9 @@ namespace Terra.Arbitrator
 
 
                 foreach (var entry in diff)
                 foreach (var entry in diff)
                 {
                 {
-                    if (entry.Status == ChangeKind.Added || entry.Status == ChangeKind.Deleted || entry.Status == ChangeKind.Modified)
+                    if (entry.Status is ChangeKind.Added or ChangeKind.Deleted or ChangeKind.Modified or ChangeKind.Renamed)
                     {
                     {
-                        changes.Add(new GitChange(entry.Path, entry.Status));
+                        changes.Add(new GitChange(entry.Path, entry.OldPath, entry.Status));
                     }
                     }
                 }
                 }
                 
                 
@@ -150,6 +150,20 @@ namespace Terra.Arbitrator
                         }
                         }
                     }
                     }
                 }
                 }
+                else if (changeToReset.Status == ChangeKind.Renamed)
+                {
+                    // 1. Unstage the new path
+                    Commands.Unstage(repo, changeToReset.FilePath);
+                    // 2. Delete the new file from the working directory
+                    if (projectRoot != null)
+                    {
+                        var newFullPath = Path.Combine(projectRoot, changeToReset.FilePath);
+                        if (File.Exists(newFullPath)) File.Delete(newFullPath);
+                    }
+
+                    // 3. Checkout the old path from the HEAD to restore it
+                    repo.CheckoutPaths(repo.Head.Tip.Sha, new[] { changeToReset.OldFilePath }, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
+                }
                 else
                 else
                 {
                 {
                     // For Modified or Deleted files, CheckoutPaths is the correct command to revert them.
                     // For Modified or Deleted files, CheckoutPaths is the correct command to revert them.
@@ -171,10 +185,22 @@ namespace Terra.Arbitrator
                 var projectRoot = Directory.GetParent(Application.dataPath)?.FullName;
                 var projectRoot = Directory.GetParent(Application.dataPath)?.FullName;
                 using var repo = new Repository(projectRoot);
                 using var repo = new Repository(projectRoot);
 
 
-                // Use Compare() against the HEAD commit to get the patch for the specific file.
-                var diff = repo.Diff.Compare<Patch>(new[] { change.FilePath }, true);
+                // Compare the HEAD tree with the working directory.
+                var patch = repo.Diff.Compare<Patch>(repo.Head.Tip.Tree, DiffTargets.WorkingDirectory);
                 
                 
-                resolve(diff.Content);
+                // Find the specific change in the complete patch by its path.
+                // For renames, the 'Path' property holds the new path, which is what we need to look up.
+                var patchEntry = patch[change.FilePath];
+
+                if (patchEntry == null)
+                {
+                    // This might happen if the change is in the index but not the working dir.
+                    // Fallback to checking the index as well.
+                    patch = repo.Diff.Compare<Patch>(repo.Head.Tip.Tree, DiffTargets.Index);
+                    patchEntry = patch[change.FilePath];
+                }
+
+                resolve(patchEntry?.Patch ?? $"No textual changes detected for {change.FilePath}. Status: {change.Status}");
             }
             }
             catch(Exception ex)
             catch(Exception ex)
             {
             {

Assets/Arbitrator/Editor/GitService.cs.meta → Assets/Arbitrator/Editor/Services/GitService.cs.meta