Skip to content

Commit 7bb94f3

Browse files
committed
feat: eliminate string-based functions
1 parent f8db77a commit 7bb94f3

File tree

4 files changed

+387
-358
lines changed

4 files changed

+387
-358
lines changed

Editor/ProjectSettingsPanel.cs

Lines changed: 120 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
using UnityEditor;
88
using UnityEngine;
99
using UnityEngine.UIElements;
10-
using Object = UnityEngine.Object;
1110

1211

1312
namespace SatorImaging.UnitySourceGenerator
1413
{
15-
internal class ProjectSettingsPanel : SettingsProvider
14+
public class ProjectSettingsPanel : SettingsProvider
1615
{
1716
const float PADDING_WIDTH = 4;
1817
const string DISPLAY_NAME = "Alternative Source Generator for Unity";
@@ -86,31 +85,38 @@ void OnGUI()
8685

8786

8887
static ProjectSettingsData _settings = ProjectSettingsData.instance;
89-
static string[] _generatorPaths = Array.Empty<string>();
90-
static bool[] _isEmitterExists = Array.Empty<bool>();
91-
static string[] _emitterPaths = Array.Empty<string>();
92-
static string _generatorPathToShowEmitters = null;
93-
static Dictionary<string, string> _generatorNameToOutputFileName = new();
94-
// GUI classes cannot be initialized on field definition.
88+
static Type _generatorTypeToShowEmittersInGUI = null;
89+
static Type[] _referencingEmittersToShowInGUI = Array.Empty<Type>();
90+
static Type[] _generatorTypes = Array.Empty<Type>();
91+
static bool[] _isGeneratorHasEmitters = Array.Empty<bool>();
92+
static Dictionary<Type, string> _targetClassToScriptFilePath = new();
93+
static Dictionary<Type, string[]> _targetClassToOutputFilePaths = new();
94+
static Dictionary<Type, string[]> _targetClassToOutputFileNames = new();
95+
// some GUI classes cannot be accessed on field definition.
9596
static GUIContent gui_emittersBtn;
9697
static GUIContent gui_deleteBtn;
9798
static GUIContent gui_runBtn;
9899
static GUIContent gui_unveilBtn;
99-
static GUILayoutOption gui_toggleWidth;
100-
static GUILayoutOption gui_buttonWidth;
101100
static GUIStyle gui_noBGButtonStyle;
102101
static GUIStyle gui_deleteMiniLabel;
102+
static GUIContent gui_suspendAutoReloadLabel = new GUIContent(" Suspend Auto Reload while Unity Editor in Background *experimental");
103+
static GUIContent gui_autoRunLabel = new GUIContent(" Auto Run Generators on Script Update / Reimport");
104+
static GUIContent gui_buttonColumnLabel = new GUIContent("On Run");
105+
static GUIContent gui_refEmittersLabel = new GUIContent("Referencing Emitters");
106+
static GUIContent gui_multiGeneratorsLabel = new GUIContent("MULTIPLE GENERATORS");
107+
static GUIContent gui_noSourceGenLabel = new GUIContent("NO SOURCE GENERATORS IN PROJECT");
108+
static GUIContent gui_debugLabel = new GUIContent("DEBUG");
109+
static GUILayoutOption gui_toggleWidth = GUILayout.Width(16);
110+
static GUILayoutOption gui_buttonWidth = GUILayout.Width(32);
103111

104112
// NOTE: class is reference type and reference type variable is "passed by value".
105113
// to take reference to newly created object, need `ref` chain.
106114
static void Wakeup(ref Editor cachedEditor)
107115
{
108116
gui_emittersBtn ??= new(EditorGUIUtility.IconContent("d_icon dropdown"));
109117
gui_deleteBtn ??= new(EditorGUIUtility.IconContent("d_TreeEditor.Trash"));
110-
gui_runBtn ??= new(EditorGUIUtility.IconContent("PlayButton On"));//d_playLoopOff
111-
gui_unveilBtn ??= new(EditorGUIUtility.IconContent("d_Linked"));//SavePassive/SaveActive/SaveFromPlay/d_pick/
112-
gui_toggleWidth ??= GUILayout.Width(16);
113-
gui_buttonWidth ??= GUILayout.Width(32);
118+
gui_runBtn ??= new(EditorGUIUtility.IconContent("PlayButton On"));
119+
gui_unveilBtn ??= new(EditorGUIUtility.IconContent("d_Linked"));
114120
if (gui_noBGButtonStyle == null)
115121
{
116122
gui_noBGButtonStyle = new(EditorStyles.iconButton);
@@ -129,18 +135,36 @@ static void Wakeup(ref Editor cachedEditor)
129135
_settings = ProjectSettingsData.instance;
130136
_settings.hideFlags = HideFlags.HideAndDontSave & ~HideFlags.NotEditable;
131137

132-
_generatorPaths = USGEngine.TypeNameToInfo
133-
// remove emitter class. it can be access thru referencing emitter list.
134-
.Where(static x => x.Value.TargetClass == null || x.Value.Attribute.GeneratorClass == null)
135-
.Select(static x => USGUtility.GetAssetPathByName(x.Key))
136-
//.Where(static x => x.StartsWith("Assets/"))
138+
// caching heavy ops
139+
_targetClassToOutputFilePaths = USGEngine.GeneratorInfoList
140+
.ToLookup(static x => x.TargetClass)
141+
.ToDictionary(
142+
static x => x.Key,
143+
static x => x.Select(static x => USGEngine.GetGeneratorOutputPath(x)).ToArray());
144+
_targetClassToOutputFileNames = _targetClassToOutputFilePaths
145+
.ToDictionary(
146+
static x => x.Key,
147+
static x => x.Value.Select(static x => Path.GetFileName(x)).ToArray());
148+
149+
_generatorTypes = USGEngine.GeneratorInfoList
150+
.Select(static x => x.Attribute.GeneratorClass)
151+
.Union(_targetClassToOutputFileNames
152+
.Where(static x => x.Value.Length > 1)
153+
.Select(static x => x.Key))
154+
.Distinct()
155+
.OrderBy(static x => x.FullName)
137156
.ToArray();
138-
_isEmitterExists = _generatorPaths
139-
.Select(static x => GetEmitters(x).Length > 0)
157+
_isGeneratorHasEmitters = _generatorTypes
158+
.Select(static x => GetReferencingEmitters(x).Length > 0)
140159
.ToArray();
141-
_emitterPaths = GetEmitters(null); //clear
142-
_generatorNameToOutputFileName = USGEngine.TypeNameToInfo
143-
.ToDictionary(static x => x.Key, static x => x.Value.OutputFileName);
160+
_referencingEmittersToShowInGUI = GetReferencingEmitters(null); // not only set variable, but clear ref emitters panel settings.
161+
162+
_targetClassToScriptFilePath = USGEngine.GeneratorInfoList
163+
.Select(static x => x.TargetClass)
164+
.Union(_generatorTypes)
165+
.ToDictionary(
166+
static x => x,
167+
static x => USGUtility.GetAssetPathByType(x) ?? throw new Exception());
144168

145169
Editor.CreateCachedEditor(_settings, null, ref cachedEditor);
146170
}
@@ -159,8 +183,8 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
159183
EditorGUILayout.BeginVertical();
160184
{
161185
EditorGUI.BeginChangeCheck();
162-
var suspendAutoReload = EditorGUILayout.ToggleLeft(" Suspend Auto Reload while Unity Editor in Background *experimental", _settings.SuspendAutoReloadWhileEditorInBackground);
163-
var autoEmit = EditorGUILayout.ToggleLeft(" Auto Run Generators on Script Update / Reimport", _settings.AutoEmitOnScriptUpdate);
186+
var suspendAutoReload = EditorGUILayout.ToggleLeft(gui_suspendAutoReloadLabel, _settings.SuspendAutoReloadWhileEditorInBackground);
187+
var autoEmit = EditorGUILayout.ToggleLeft(gui_autoRunLabel, _settings.AutoEmitOnScriptUpdate);
164188
if (EditorGUI.EndChangeCheck())
165189
{
166190
_settings.SuspendAutoReloadWhileEditorInBackground = suspendAutoReload;
@@ -169,28 +193,28 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
169193
}
170194
//EditorGUILayout.Space();
171195

172-
EditorGUILayout.LabelField("On Run", EditorStyles.miniLabel);
173-
if (_generatorPaths.Length == 0)
174-
EditorGUILayout.LabelField("NO SOURCE GENERATORS IN PROJECT");
196+
EditorGUILayout.LabelField(gui_buttonColumnLabel, EditorStyles.miniLabel);
197+
if (_generatorTypes.Length == 0)
198+
EditorGUILayout.LabelField(gui_noSourceGenLabel);
175199
else
176-
for (int i = 0; i < _generatorPaths.Length; i++)
200+
for (int i = 0; i < _generatorTypes.Length; i++)
177201
{
178-
DrawGenerator(_generatorPaths[i], _isEmitterExists[i]);
202+
DrawGenerator(_generatorTypes[i], _isGeneratorHasEmitters[i]);
179203
}
180204
EditorGUILayout.Space();
181205

182-
EditorGUILayout.LabelField("Referencing Emitters");
183-
if (_generatorPathToShowEmitters != null)
206+
if (_generatorTypeToShowEmittersInGUI != null)
184207
{
185-
for (int i = 0; i < _emitterPaths.Length; i++)
208+
EditorGUILayout.LabelField(gui_refEmittersLabel, EditorStyles.largeLabel);
209+
for (int i = 0; i < _referencingEmittersToShowInGUI.Length; i++)
186210
{
187-
DrawGenerator(_emitterPaths[i], false);
211+
DrawGenerator(_referencingEmittersToShowInGUI[i], false);
188212
}
189213
}
190214
EditorGUILayout.Space();
191215

192216
GUILayout.FlexibleSpace();
193-
_debugFoldout = EditorGUILayout.Foldout(_debugFoldout, "DEBUG", true);
217+
_debugFoldout = EditorGUILayout.Foldout(_debugFoldout, gui_debugLabel, true);
194218
if (_debugFoldout)
195219
{
196220
cachedEditor.OnInspectorGUI();
@@ -208,11 +232,12 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
208232
}
209233

210234

211-
static void DrawGenerator(string filePath, bool showEmitterBtn)
235+
static void DrawGenerator(Type t, bool showEmitterBtn)//string filePath, bool showEmitterBtn)
212236
{
213237
EditorGUILayout.BeginHorizontal();
214238
{
215-
var fileName = Path.GetFileNameWithoutExtension(filePath);
239+
// NOTE: USGUtility functions are heavy for use in GUI loops, cache it!!
240+
var filePath = _targetClassToScriptFilePath[t];
216241

217242
EditorGUI.BeginChangeCheck();
218243
var isOn = EditorGUILayout.Toggle(!_settings.AutoEmitDisabledPaths.Contains(filePath), gui_toggleWidth);
@@ -229,53 +254,71 @@ static void DrawGenerator(string filePath, bool showEmitterBtn)
229254
//run
230255
if (GUILayout.Button(gui_runBtn, gui_buttonWidth))
231256
{
232-
Debug.Log($"[{nameof(UnitySourceGenerator)}] Generator running: {fileName}");
233-
USGUtility.ForceGenerateByName(fileName, false);
257+
Debug.Log($"[{nameof(UnitySourceGenerator)}] Generator running: {t.FullName}");
258+
USGUtility.ForceGenerateByType(t, false);
234259
}
235260

236261
//label
237-
if (EditorGUILayout.LinkButton(fileName))
262+
if (EditorGUILayout.LinkButton(t.Name))
238263
{
239-
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(filePath));
264+
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<MonoScript>(filePath));
240265
}
241266

242267
//emitters??
243268
if (showEmitterBtn)
244269
{
245270
if (GUILayout.Button(gui_emittersBtn, gui_noBGButtonStyle))
246271
{
247-
_emitterPaths = GetEmitters(filePath);
272+
_referencingEmittersToShowInGUI = GetReferencingEmitters(t);
248273
}
249274
}
250275
//unveil??
251276
else
252277
{
253-
if (GUILayout.Button(gui_unveilBtn, gui_noBGButtonStyle))
254-
{
255-
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(
256-
USGEngine.GetGeneratorOutputPath(filePath, _generatorNameToOutputFileName[fileName])));
257-
}
278+
if (_targetClassToOutputFilePaths.ContainsKey(t))
279+
for (int i = 0; i < _targetClassToOutputFilePaths[t].Length; i++)
280+
{
281+
if (GUILayout.Button(gui_unveilBtn, gui_noBGButtonStyle))
282+
{
283+
EditorGUIUtility.PingObject(
284+
AssetDatabase.LoadAssetAtPath<MonoScript>(_targetClassToOutputFilePaths[t][i]));
285+
}
286+
}
258287
}
259288

260289
//deleteBtn
261-
if (_generatorNameToOutputFileName[fileName]?.Length is > 0)
290+
if (_targetClassToOutputFilePaths.ContainsKey(t))
262291
{
263-
GUILayout.FlexibleSpace();
264-
if (EditorGUIUtility.currentViewWidth > _settings.DenseViewWidthThreshold)
265-
GUILayout.Label(_generatorNameToOutputFileName[fileName], gui_deleteMiniLabel);
266-
if (GUILayout.Button(gui_deleteBtn))//, gui_noBGButtonStyle))
292+
if (_targetClassToOutputFilePaths[t].Length == 1)
293+
{
294+
GUILayout.FlexibleSpace();
295+
if (EditorGUIUtility.currentViewWidth > _settings.DenseViewWidthThreshold)
296+
GUILayout.Label(_targetClassToOutputFileNames[t][0], gui_deleteMiniLabel);
297+
}
298+
else
267299
{
268-
var genFullPath = USGEngine.GetGeneratorOutputPath(filePath, _generatorNameToOutputFileName[fileName]);
269-
if (EditorUtility.DisplayDialog(nameof(UnitySourceGenerator),
270-
$"Would you like to delete emitted file?\n" +
271-
$"- {_generatorNameToOutputFileName[fileName]}\n" +
272-
$"\n" +
273-
$"File Path: {genFullPath}",
274-
"Yes", "cancel"))
300+
GUILayout.FlexibleSpace();
301+
//if (EditorGUIUtility.currentViewWidth > _settings.DenseViewWidthThreshold)
302+
// GUILayout.Label(gui_multiGeneratorsLabel, gui_deleteMiniLabel);
303+
}
304+
305+
for (int i = 0; i < _targetClassToOutputFilePaths[t].Length; i++)
306+
{
307+
if (GUILayout.Button(gui_deleteBtn))
275308
{
276-
File.Delete(genFullPath);
277-
Debug.Log($"[{nameof(UnitySourceGenerator)}] File is deleted: {genFullPath}");
278-
AssetDatabase.Refresh();
309+
if (File.Exists(_targetClassToOutputFilePaths[t][i])
310+
&& EditorUtility.DisplayDialog(
311+
nameof(UnitySourceGenerator),
312+
$"Would you like to delete emitted file?\n" +
313+
$"- {_targetClassToOutputFileNames[t][i]}\n" +
314+
$"\n" +
315+
$"File Path: {_targetClassToOutputFilePaths[t][i]}",
316+
"Yes", "cancel"))
317+
{
318+
File.Delete(_targetClassToOutputFilePaths[t][i]);
319+
Debug.Log($"[{nameof(UnitySourceGenerator)}] File is deleted: {_targetClassToOutputFilePaths[t][i]}");
320+
AssetDatabase.Refresh();
321+
}
279322
}
280323
}
281324
}
@@ -284,18 +327,22 @@ static void DrawGenerator(string filePath, bool showEmitterBtn)
284327
}
285328

286329

287-
static string[] GetEmitters(string generatorPath)
330+
static Type[] GetReferencingEmitters(Type t)
288331
{
289-
_generatorPathToShowEmitters = generatorPath;
290-
if (string.IsNullOrEmpty(generatorPath))
291-
return Array.Empty<string>();
292-
293-
var clsName = Path.GetFileNameWithoutExtension(generatorPath);
294-
return USGEngine.TypeNameToInfo
295-
.Where(x => x.Value.Attribute.GeneratorClass?.Name == clsName || x.Value.TargetClass?.Name == clsName)
296-
.Select(static x => USGUtility.GetAssetPathByName(x.Key))
297-
.Where(x => x != generatorPath) // remove itself
332+
_generatorTypeToShowEmittersInGUI = t;
333+
if (t == null)
334+
return Array.Empty<Type>();
335+
336+
// NOTE: self-emit generator can have other target.
337+
var ret = USGEngine.GeneratorInfoList
338+
.Where(x => x.Attribute.GeneratorClass == t)
339+
.Select(static x => x.TargetClass)
298340
.ToArray();
341+
342+
if (ret.Length == 1 && ret[0] == t)
343+
return Array.Empty<Type>();
344+
345+
return ret;
299346
}
300347

301348

0 commit comments

Comments
 (0)