// Copyright (c) 2025 TerraByte Inc. // // A modal editor window for displaying text differences (diffs) and // confirming an action with the user. using System; using System.IO; using UnityEditor; using UnityEngine; namespace Terra.Arbitrator { public class DiffWindow : EditorWindow { private string _filePath; private string _diffContent; private Action _onCloseCallback; private Vector2 _scrollPosition; private bool _callbackInvoked = false; /// /// Shows a modal window to display the diff and get user confirmation. /// /// The path of the file being diffed. /// The diff text to display. /// A callback that returns true if the user confirmed, otherwise false. public static void ShowWindow(string filePath, string diffContent, Action onCloseCallback) { DiffWindow window = GetWindow(true, "Diff Viewer", true); window.titleContent = new GUIContent($"Diff: {Path.GetFileName(filePath)}"); window.minSize = new Vector2(700, 500); window._filePath = filePath; window._diffContent = diffContent; window._onCloseCallback = onCloseCallback; window._callbackInvoked = false; window.ShowModalUtility(); // Show as a blocking modal window } private void OnGUI() { EditorGUILayout.LabelField(_filePath, EditorStyles.boldLabel); // Create a custom style for the diff text for better readability var diffStyle = new GUIStyle(EditorStyles.textArea) { richText = true, wordWrap = false }; _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, EditorStyles.helpBox, GUILayout.ExpandHeight(true)); EditorGUILayout.SelectableLabel(GetColoredDiff(_diffContent), diffStyle, GUILayout.ExpandHeight(true)); EditorGUILayout.EndScrollView(); EditorGUILayout.Space(); EditorGUILayout.HelpBox("Review the changes above. Green lines are additions, red lines are deletions. Reverting will permanently discard these changes.", MessageType.Warning); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Revert Changes", GUILayout.Height(30), GUILayout.Width(150))) { _callbackInvoked = true; _onCloseCallback?.Invoke(true); Close(); } if (GUILayout.Button("Cancel", GUILayout.Height(30), GUILayout.Width(120))) { // Let OnDestroy handle the callback Close(); } EditorGUILayout.EndHorizontal(); } private static string GetColoredDiff(string rawDiff) { var coloredDiff = ""; var lines = rawDiff.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (line.StartsWith("+")) { coloredDiff += $"{line}\n"; } else if (line.StartsWith("-")) { coloredDiff += $"{line}\n"; } else if (line.StartsWith("@@")) { coloredDiff += $"{line}\n"; } else { coloredDiff += $"{line}\n"; } } return coloredDiff; } private void OnDestroy() { // This is called when the window is closed by any means. // If the callback hasn't been invoked yet (i.e., user clicked 'X' or 'Cancel'), // we invoke it with 'false' to signify cancellation. if (!_callbackInvoked) { _onCloseCallback?.Invoke(false); } } } }