Browse Source

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

Sujith:) 1 month ago
parent
commit
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 UnityEditor;
 using LibGit2Sharp;
+using Terra.Arbitrator.Services;
 using System.Collections.Generic;
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.GUI
 {
     public class ArbitratorWindow : EditorWindow
     {
@@ -27,6 +28,8 @@ namespace Terra.Arbitrator
         private string _errorMessage;
         private bool _isLoading;
         private string _loadingMessage = "";
+        private GUIStyle _evenRowStyle;
+        private bool _stylesInitialized;
 
         [MenuItem("Terra/Changes")]
         public static void ShowWindow()
@@ -43,9 +46,35 @@ namespace Terra.Arbitrator
         {
             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()
         {
+            InitializeStyles();
+            
             // --- Top Toolbar ---
             DrawToolbar();
             
@@ -63,11 +92,7 @@ namespace Terra.Arbitrator
             }
 
             // --- 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();
                 DrawCommitSection();
@@ -86,13 +111,27 @@ namespace Terra.Arbitrator
         private void DrawToolbar()
         {
             EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
-
+            EditorGUI.BeginDisabledGroup(_isLoading);
             // 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)))
             {
                 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.
             GUILayout.FlexibleSpace();
 
@@ -107,6 +146,15 @@ namespace Terra.Arbitrator
 
             EditorGUILayout.EndHorizontal();
         }
+        
+        private void SetAllSelection(bool selected)
+        {
+            if (_changes == null) return;
+            foreach (var change in _changes)
+            {
+                change.IsSelectedForCommit = selected;
+            }
+        }
 
         private void HandleCompare()
         {
@@ -222,45 +270,52 @@ namespace Terra.Arbitrator
 
             // --- Draw Scrollable List ---
             _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));
-
-                // Column 2: Status
+                
                 string status;
                 Color statusColor;
+                string filePathDisplay;
+
                 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.Renamed:
                     case ChangeKind.Copied:
                     case ChangeKind.Ignored:
                     case ChangeKind.Untracked:
                     case ChangeKind.TypeChanged:
                     case ChangeKind.Unreadable:
                     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));
-                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);
                 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);
                 }
                 EditorGUI.EndDisabledGroup();
@@ -281,6 +336,7 @@ namespace Terra.Arbitrator
             EditorGUI.BeginDisabledGroup(isPushDisabled);
             if (GUILayout.Button("Commit & Push Selected Files", GUILayout.Height(40)))
             {
+                Debug.Log("Commit & Push Selected Files");
                 HandleCommitAndPush();
             }
             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 UnityEngine;
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.GUI
 {
     public class DiffWindow : EditorWindow
     {
@@ -16,7 +16,8 @@ namespace Terra.Arbitrator
         private string _diffContent;
         private Action<bool> _onCloseCallback;
         private Vector2 _scrollPosition;
-        private bool _callbackInvoked = false;
+        private bool _callbackInvoked;
+        private GUIStyle _diffStyle;
 
         /// <summary>
         /// 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>
         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.minSize = new Vector2(700, 500);
             window._filePath = filePath;
@@ -36,19 +37,33 @@ namespace Terra.Arbitrator
             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,
-                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.Space();
@@ -64,7 +79,6 @@ namespace Terra.Arbitrator
             }
             if (GUILayout.Button("Cancel", GUILayout.Height(30), GUILayout.Width(120)))
             {
-                // Let OnDestroy handle the callback
                 Close();
             }
             EditorGUILayout.EndHorizontal();
@@ -93,7 +107,7 @@ namespace Terra.Arbitrator
                     coloredDiff += $"{line}\n";
                 }
             }
-            return coloredDiff;
+            return coloredDiff + "\n";
         }
 
         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;
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.Services
 {
     /// <summary>
     /// A data container for a single file change detected by Git.
@@ -18,6 +18,7 @@ namespace Terra.Arbitrator
     public class GitChange
     {
         public string FilePath { get; private set; }
+        public string OldFilePath { get; private set; }
         public ChangeKind Status { get; private set; }
         
         /// <summary>
@@ -25,9 +26,10 @@ namespace Terra.Arbitrator
         /// </summary>
         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;
             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.IO;
-using UnityEngine;
 using LibGit2Sharp;
+using UnityEngine;
 using Terra.Arbitrator.Promises;
 using System.Collections.Generic;
 
-namespace Terra.Arbitrator
+namespace Terra.Arbitrator.Services
 {
     public static class GitService
     {
@@ -68,9 +68,9 @@ namespace Terra.Arbitrator
 
                 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
                 {
                     // 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;
                 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)
             {

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